Exemple #1
0
HRESULT WINAPI fnTextSrv_TxSetText(ITextServices *iface,
                                   LPCWSTR pszText)
{
    ICOM_THIS_MULTI(ITextServicesImpl, lpVtbl, iface);
    ME_Cursor cursor;

    ME_SetCursorToStart(This->editor, &cursor);
    ME_InternalDeleteText(This->editor, &cursor,
                          ME_GetTextLength(This->editor), FALSE);
    ME_InsertTextFromCursor(This->editor, 0, pszText, -1,
                            This->editor->pBuffer->pDefaultStyle);
    ME_SetSelection(This->editor, 0, 0);
    This->editor->nModifyStep = 0;
    OleFlushClipboard();
    ME_EmptyUndoStack(This->editor);
    ME_UpdateRepaint(This->editor);

    return S_OK;
}
Exemple #2
0
DECLSPEC_HIDDEN HRESULT WINAPI fnTextSrv_TxGetText(ITextServices *iface, BSTR *pbstrText)
{
   ITextServicesImpl *This = impl_from_ITextServices(iface);
   int length;

   length = ME_GetTextLength(This->editor);
   if (length)
   {
      ME_Cursor start;
      BSTR bstr;
      bstr = SysAllocStringByteLen(NULL, length * sizeof(WCHAR));
      if (bstr == NULL)
         return E_OUTOFMEMORY;

      ME_CursorFromCharOfs(This->editor, 0, &start);
      ME_GetTextW(This->editor, bstr, length, &start, INT_MAX, FALSE, FALSE);
      *pbstrText = bstr;
   } else {
      *pbstrText = NULL;
   }

   return S_OK;
}
Exemple #3
0
int ME_SetSelection(ME_TextEditor *editor, int from, int to)
{
  int selectionEnd = 0;
  const int len = ME_GetTextLength(editor);

  /* all negative values are effectively the same */
  if (from < 0)
    from = -1;
  if (to < 0)
    to = -1;

  /* select all */
  if (from == 0 && to == -1)
  {
    editor->pCursors[1].pRun = ME_FindItemFwd(editor->pBuffer->pFirst, diRun);
    editor->pCursors[1].nOffset = 0; 
    editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun); 
    editor->pCursors[0].nOffset = 0;
    ME_InvalidateSelection(editor);
    ME_ClearTempStyle(editor);
    return len + 1;
  }

  /* if both values are equal and also out of bound, that means to */
  /* put the selection at the end of the text */
  if ((from == to) && (to < 0 || to > len))
  {
    selectionEnd = 1;
  }
  else
  {
    /* if from is negative and to is positive then selection is */
    /* deselected and caret moved to end of the current selection */
    if (from < 0)
    {
      int start, end;
      ME_GetSelection(editor, &start, &end);
      editor->pCursors[1] = editor->pCursors[0];
      ME_Repaint(editor);
      ME_ClearTempStyle(editor);
      return end;
    }

    /* adjust to if it's a negative value */
    if (to < 0)
      to = len + 1;

    /* flip from and to if they are reversed */
    if (from>to)
    {
      int tmp = from;
      from = to;
      to = tmp;
    }

    /* after fiddling with the values, we find from > len && to > len */
    if (from > len)
      selectionEnd = 1;
    /* special case with to too big */
    else if (to > len)
      to = len + 1;
  }

  if (selectionEnd)
  {
    editor->pCursors[1].pRun = editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
    editor->pCursors[1].nOffset = editor->pCursors[0].nOffset = 0;
    ME_InvalidateSelection(editor);
    ME_ClearTempStyle(editor);
    return len;
  }

  ME_RunOfsFromCharOfs(editor, from, &editor->pCursors[1].pRun, &editor->pCursors[1].nOffset);
  ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset);
  return to;
}
Exemple #4
0
void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 
  const WCHAR *str, int len, ME_Style *style)
{
  const WCHAR *pos;
  ME_Cursor *p = NULL;
  int oldLen;

  /* FIXME really HERE ? */
  if (ME_IsSelection(editor))
    ME_DeleteSelection(editor);

  /* FIXME: is this too slow? */
  /* Didn't affect performance for WM_SETTEXT (around 50sec/30K) */
  oldLen = ME_GetTextLength(editor);

  /* text operations set modified state */
  editor->nModifyStep = 1;

  assert(style);

  assert(nCursor>=0 && nCursor<editor->nCursors);
  if (len == -1)
    len = lstrlenW(str);

  /* grow the text limit to fit our text */
  if(editor->nTextLimit < oldLen +len)
    editor->nTextLimit = oldLen + len;

  while (len)
  {
    pos = str;
    /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
    while(pos-str < len && *pos != '\r' && *pos != '\n' && *pos != '\t')
      pos++;
    if (pos-str < len && *pos == '\t') { /* handle tabs */
      WCHAR tab = '\t';

      if (pos!=str)
        ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
    
      ME_InternalInsertTextFromCursor(editor, nCursor, &tab, 1, style, MERF_TAB);
 
      pos++;
      if(pos-str <= len) {
        len -= pos - str;
        str = pos;
        continue;
      }
    }
    /* handle special \r\r\n sequence (richedit 2.x and higher only) */
    if (!editor->bEmulateVersion10 && pos-str < len-2 && pos[0] == '\r' && pos[1] == '\r' && pos[2] == '\n') {
      WCHAR space = ' ';

      if (pos!=str)
        ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);

      ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, style, 0);

      pos+=3;
      if(pos-str <= len) {
        len -= pos - str;
        str = pos;
        continue;
      }
    }
    if (pos-str < len) {   /* handle EOLs */
      ME_DisplayItem *tp, *end_run;
      ME_Style *tmp_style;
      int numCR, numLF;

      if (pos!=str)
        ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
      p = &editor->pCursors[nCursor];
      if (p->nOffset) {
        ME_SplitRunSimple(editor, p->pRun, p->nOffset);
        p = &editor->pCursors[nCursor];
      }
      tmp_style = ME_GetInsertStyle(editor, nCursor);
      /* ME_SplitParagraph increases style refcount */

      /* Encode and fill number of CR and LF according to emulation mode */
      if (editor->bEmulateVersion10) {
        const WCHAR * tpos;

        /* We have to find out how many consecutive \r are there, and if there
           is a \n terminating the run of \r's. */
        numCR = 0; numLF = 0;
        tpos = pos;
        while (tpos-str < len && *tpos == '\r') {
          tpos++;
          numCR++;
        }
        if (tpos-str >= len) {
          /* Reached end of text without finding anything but '\r' */
          if (tpos != pos) {
            pos++;
          }
          numCR = 1; numLF = 0;
        } else if (*tpos == '\n') {
          /* The entire run of \r's plus the one \n is one single line break */
          pos = tpos + 1;
          numLF = 1;
        } else {
          /* Found some other content past the run of \r's */
          pos++;
          numCR = 1; numLF = 0;
        }
      } else {
        if(pos-str < len && *pos =='\r')
          pos++;
        if(pos-str < len && *pos =='\n')
          pos++;
        numCR = 1; numLF = 0;
      }
      tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style, numCR, numLF, 0);
      p->pRun = ME_FindItemFwd(tp, diRun);
      end_run = ME_FindItemBack(tp, diRun);
      ME_ReleaseStyle(end_run->member.run.style);
      end_run->member.run.style = tmp_style;
      p->nOffset = 0;

      if(pos-str <= len) {
        len -= pos - str;
        str = pos;
        continue;
      }
    }
    ME_InternalInsertTextFromCursor(editor, nCursor, str, len, style, 0);
    len = 0;
  }
}
Exemple #5
0
/* Move the cursor nRelOfs characters (either forwards or backwards)
 *
 * returns the actual number of characters moved.
 **/
int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs)
{
  cursor->nOffset += nRelOfs;
  if (cursor->nOffset < 0)
  {
    cursor->nOffset += cursor->pRun->member.run.nCharOfs;
    if (cursor->nOffset >= 0)
    {
      /* new offset in the same paragraph */
      do {
        cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
      } while (cursor->nOffset < cursor->pRun->member.run.nCharOfs);
      cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
      return nRelOfs;
    }

    cursor->nOffset += cursor->pPara->member.para.nCharOfs;
    if (cursor->nOffset <= 0)
    {
      /* moved to the start of the text */
      nRelOfs -= cursor->nOffset;
      ME_SetCursorToStart(editor, cursor);
      return nRelOfs;
    }

    /* new offset in a previous paragraph */
    do {
      cursor->pPara = cursor->pPara->member.para.prev_para;
    } while (cursor->nOffset < cursor->pPara->member.para.nCharOfs);
    cursor->nOffset -= cursor->pPara->member.para.nCharOfs;

    cursor->pRun = ME_FindItemBack(cursor->pPara->member.para.next_para, diRun);
    while (cursor->nOffset < cursor->pRun->member.run.nCharOfs) {
      cursor->pRun = ME_FindItemBack(cursor->pRun, diRun);
    }
    cursor->nOffset -= cursor->pRun->member.run.nCharOfs;
  } else if (cursor->nOffset >= cursor->pRun->member.run.len) {
    ME_DisplayItem *next_para;
    int new_offset;

    new_offset = ME_GetCursorOfs(cursor);
    next_para = cursor->pPara->member.para.next_para;
    if (new_offset < next_para->member.para.nCharOfs)
    {
      /* new offset in the same paragraph */
      do {
        cursor->nOffset -= cursor->pRun->member.run.len;
        cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
      } while (cursor->nOffset >= cursor->pRun->member.run.len);
      return nRelOfs;
    }

    if (new_offset >= ME_GetTextLength(editor))
    {
      /* new offset at the end of the text */
      ME_SetCursorToEnd(editor, cursor);
      nRelOfs -= new_offset - ME_GetTextLength(editor);
      return nRelOfs;
    }

    /* new offset in a following paragraph */
    do {
      cursor->pPara = next_para;
      next_para = next_para->member.para.next_para;
    } while (new_offset >= next_para->member.para.nCharOfs);

    cursor->nOffset = new_offset - cursor->pPara->member.para.nCharOfs;
    cursor->pRun = ME_FindItemFwd(cursor->pPara, diRun);
    while (cursor->nOffset >= cursor->pRun->member.run.len)
    {
      cursor->nOffset -= cursor->pRun->member.run.len;
      cursor->pRun = ME_FindItemFwd(cursor->pRun, diRun);
    }
  } /* else new offset is in the same run */
  return nRelOfs;
}
Exemple #6
0
void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 
  const WCHAR *str, int len, ME_Style *style)
{
  const WCHAR *pos;
  ME_Cursor *p = NULL;
  int oldLen;

  /* FIXME really HERE ? */
  if (ME_IsSelection(editor))
    ME_DeleteSelection(editor);

  /* FIXME: is this too slow? */
  /* Didn't affect performance for WM_SETTEXT (around 50sec/30K) */
  oldLen = ME_GetTextLength(editor);

  /* text operations set modified state */
  editor->nModifyStep = 1;

  assert(style);

  assert(nCursor>=0 && nCursor<editor->nCursors);
  if (len == -1)
    len = lstrlenW(str);

  /* grow the text limit to fit our text */
  if(editor->nTextLimit < oldLen +len)
    editor->nTextLimit = oldLen + len;

  pos = str;

  while (len)
  {
    /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
    while(pos - str < len && *pos != '\r' && *pos != '\n' && *pos != '\t')
      pos++;

    if (pos != str) { /* handle text */
      ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
    } else if (*pos == '\t') { /* handle tabs */
      WCHAR tab = '\t';
      ME_InternalInsertTextFromCursor(editor, nCursor, &tab, 1, style, MERF_TAB);
      pos++;
    } else { /* handle EOLs */
      ME_DisplayItem *tp, *end_run, *run, *prev;
      ME_Style *tmp_style;
      int eol_len = 0;

      /* Find number of CR and LF in end of paragraph run */
      if (*pos =='\r')
      {
        if (len > 1 && pos[1] == '\n')
          eol_len = 2;
        else if (len > 2 && pos[1] == '\r' && pos[2] == '\n')
          eol_len = 3;
        else
          eol_len = 1;
      } else {
        assert(*pos == '\n');
        eol_len = 1;
      }
      pos += eol_len;

      if (!editor->bEmulateVersion10 && eol_len == 3)
      {
        /* handle special \r\r\n sequence (richedit 2.x and higher only) */
        WCHAR space = ' ';
        ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, style, 0);
      } else {
        const WCHAR cr = '\r', *eol_str = str;

        if (!editor->bEmulateVersion10)
        {
          eol_str = &cr;
          eol_len = 1;
        }

        p = &editor->pCursors[nCursor];

        if (p->nOffset == p->pRun->member.run.len)
        {
           run = ME_FindItemFwd( p->pRun, diRun );
           if (!run) run = p->pRun;
        }
        else
        {
          if (p->nOffset) ME_SplitRunSimple(editor, p);
          run = p->pRun;
        }

        tmp_style = ME_GetInsertStyle(editor, nCursor);
        /* ME_SplitParagraph increases style refcount */
        tp = ME_SplitParagraph(editor, run, run->member.run.style, eol_str, eol_len, 0);

        end_run = ME_FindItemBack(tp, diRun);
        ME_ReleaseStyle(end_run->member.run.style);
        end_run->member.run.style = tmp_style;

        /* Move any cursors that were at the end of the previous run to the beginning of the new para */
        prev = ME_FindItemBack( end_run, diRun );
        if (prev)
        {
          int i;
          for (i = 0; i < editor->nCursors; i++)
          {
            if (editor->pCursors[i].pRun == prev &&
                editor->pCursors[i].nOffset == prev->member.run.len)
            {
              editor->pCursors[i].pPara = tp;
              editor->pCursors[i].pRun = run;
              editor->pCursors[i].nOffset = 0;
            }
          }
        }

      }
    }
    len -= pos - str;
    str = pos;
  }
}
Exemple #7
0
BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start,
                           int nChars, BOOL bForce)
{
  ME_Cursor c = *start;
  int nOfs = ME_GetCursorOfs(start), text_len = ME_GetTextLength( editor );
  int shift = 0;
  int totalChars = nChars;
  ME_DisplayItem *start_para;
  BOOL delete_all = FALSE;

  /* Prevent deletion past last end of paragraph run. */
  nChars = min(nChars, text_len - nOfs);
  if (nChars == text_len) delete_all = TRUE;
  start_para = c.pPara;

  if (!bForce)
  {
    ME_ProtectPartialTableDeletion(editor, &c, &nChars);
    if (nChars == 0)
      return FALSE;
  }

  while(nChars > 0)
  {
    ME_Run *run;
    ME_CursorFromCharOfs(editor, nOfs+nChars, &c);
    if (!c.nOffset &&
        nOfs+nChars == (c.pRun->member.run.nCharOfs
                        + c.pPara->member.para.nCharOfs))
    {
      /* We aren't deleting anything in this run, so we will go back to the
       * last run we are deleting text in. */
      ME_PrevRun(&c.pPara, &c.pRun);
      c.nOffset = c.pRun->member.run.len;
    }
    run = &c.pRun->member.run;
    if (run->nFlags & MERF_ENDPARA) {
      int eollen = c.pRun->member.run.len;
      BOOL keepFirstParaFormat;

      if (!ME_FindItemFwd(c.pRun, diParagraph))
      {
        return TRUE;
      }
      keepFirstParaFormat = (totalChars == nChars && nChars <= eollen &&
                             run->nCharOfs);
      if (!editor->bEmulateVersion10) /* v4.1 */
      {
        ME_DisplayItem *next_para = ME_FindItemFwd(c.pRun, diParagraphOrEnd);
        ME_DisplayItem *this_para = next_para->member.para.prev_para;

        /* The end of paragraph before a table row is only deleted if there
         * is nothing else on the line before it. */
        if (this_para == start_para &&
            next_para->member.para.nFlags & MEPF_ROWSTART)
        {
          /* If the paragraph will be empty, then it should be deleted, however
           * it still might have text right now which would inherit the
           * MEPF_STARTROW property if we joined it right now.
           * Instead we will delete it after the preceding text is deleted. */
          if (nOfs > this_para->member.para.nCharOfs) {
            /* Skip this end of line. */
            nChars -= (eollen < nChars) ? eollen : nChars;
            continue;
          }
          keepFirstParaFormat = TRUE;
        }
      }
      ME_JoinParagraphs(editor, c.pPara, keepFirstParaFormat);
      /* ME_SkipAndPropagateCharOffset(p->pRun, shift); */
      ME_CheckCharOffsets(editor);
      nChars -= (eollen < nChars) ? eollen : nChars;
      continue;
    }
    else
    {
      ME_Cursor cursor;
      int nCharsToDelete = min(nChars, c.nOffset);
      int i;

      c.nOffset -= nCharsToDelete;

      ME_FindItemBack(c.pRun, diParagraph)->member.para.nFlags |= MEPF_REWRAP;

      cursor = c;
      /* nChars is the number of characters that should be deleted from the
         PRECEDING runs (these BEFORE cursor.pRun)
         nCharsToDelete is a number of chars to delete from THIS run */
      nChars -= nCharsToDelete;
      shift -= nCharsToDelete;
      TRACE("Deleting %d (remaning %d) chars at %d in %s (%d)\n",
        nCharsToDelete, nChars, c.nOffset,
        debugstr_run( run ), run->len);

      /* nOfs is a character offset (from the start of the document
         to the current (deleted) run */
      add_undo_insert_run( editor, nOfs + nChars, get_text( run, c.nOffset ), nCharsToDelete, run->nFlags, run->style );

      ME_StrDeleteV(run->para->text, run->nCharOfs + c.nOffset, nCharsToDelete);
      run->len -= nCharsToDelete;
      TRACE("Post deletion string: %s (%d)\n", debugstr_run( run ), run->len);
      TRACE("Shift value: %d\n", shift);

      /* update cursors (including c) */
      for (i=-1; i<editor->nCursors; i++) {
        ME_Cursor *pThisCur = editor->pCursors + i;
        if (i == -1) pThisCur = &c;
        if (pThisCur->pRun == cursor.pRun) {
          if (pThisCur->nOffset > cursor.nOffset) {
            if (pThisCur->nOffset-cursor.nOffset < nCharsToDelete)
              pThisCur->nOffset = cursor.nOffset;
            else
              pThisCur->nOffset -= nCharsToDelete;
            assert(pThisCur->nOffset >= 0);
            assert(pThisCur->nOffset <= run->len);
          }
          if (pThisCur->nOffset == run->len)
          {
            pThisCur->pRun = ME_FindItemFwd(pThisCur->pRun, diRunOrParagraphOrEnd);
            assert(pThisCur->pRun->type == diRun);
            pThisCur->nOffset = 0;
          }
        }
      }

      /* c = updated data now */

      if (c.pRun == cursor.pRun)
        ME_SkipAndPropagateCharOffset(c.pRun, shift);
      else
        ME_PropagateCharOffset(c.pRun, shift);

      if (!cursor.pRun->member.run.len)
      {
        TRACE("Removing empty run\n");
        ME_Remove(cursor.pRun);
        ME_DestroyDisplayItem(cursor.pRun);
      }

      shift = 0;
      /*
      ME_CheckCharOffsets(editor);
      */
      continue;
    }
  }
  if (delete_all) ME_SetDefaultParaFormat( editor, start_para->member.para.pFmt );
  return TRUE;
}
Exemple #8
0
int ME_SetSelection(ME_TextEditor *editor, int from, int to)
{
  int selectionEnd = 0;
  const int len = ME_GetTextLength(editor);

  /* all negative values are effectively the same */
  if (from < 0)
    from = -1;
  if (to < 0)
    to = -1;

  /* select all */
  if (from == 0 && to == -1)
  {
    ME_SetCursorToStart(editor, &editor->pCursors[1]);
    ME_SetCursorToEnd(editor, &editor->pCursors[0]);
    editor->pCursors[0].nOffset = editor->pCursors[0].pRun->member.run.len;
    ME_InvalidateSelection(editor);
    return len + 1;
  }

  /* if both values are equal and also out of bound, that means to */
  /* put the selection at the end of the text */
  if ((from == to) && (to < 0 || to > len))
  {
    selectionEnd = 1;
  }
  else
  {
    /* if from is negative and to is positive then selection is */
    /* deselected and caret moved to end of the current selection */
    if (from < 0)
    {
      int start, end;
      ME_GetSelectionOfs(editor, &start, &end);
      if (start != end)
      {
          if (end > len)
          {
              editor->pCursors[0].nOffset = 0;
              end --;
          }
          editor->pCursors[1] = editor->pCursors[0];
          ME_Repaint(editor);
      }
      return end;
    }

    /* adjust to if it's a negative value */
    if (to < 0)
      to = len + 1;

    /* flip from and to if they are reversed */
    if (from>to)
    {
      int tmp = from;
      from = to;
      to = tmp;
    }

    /* after fiddling with the values, we find from > len && to > len */
    if (from > len)
      selectionEnd = 1;
    /* special case with to too big */
    else if (to > len)
      to = len + 1;
  }

  if (selectionEnd)
  {
    ME_SetCursorToEnd(editor, &editor->pCursors[0]);
    editor->pCursors[1] = editor->pCursors[0];
    ME_InvalidateSelection(editor);
    return len;
  }

  ME_CursorFromCharOfs(editor, from, &editor->pCursors[1]);
  editor->pCursors[0] = editor->pCursors[1];
  ME_MoveCursorChars(editor, &editor->pCursors[0], to - from);
  /* Selection is not allowed in the middle of an end paragraph run. */
  if (editor->pCursors[1].pRun->member.run.nFlags & MERF_ENDPARA)
    editor->pCursors[1].nOffset = 0;
  if (editor->pCursors[0].pRun->member.run.nFlags & MERF_ENDPARA)
  {
    if (to > len)
      editor->pCursors[0].nOffset = editor->pCursors[0].pRun->member.run.len;
    else
      editor->pCursors[0].nOffset = 0;
  }
  return to;
}
Exemple #9
0
void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor, 
  const WCHAR *str, int len, ME_Style *style)
{
  const WCHAR *pos;
  ME_Cursor *p = NULL;
  /* FIXME: is this too slow? */
  /* Didn't affect performance for WM_SETTEXT (around 50sec/30K) */
  int freeSpace = editor->nTextLimit - ME_GetTextLength(editor);

  /* text operations set modified state */
  editor->nModifyStep = 1;

  assert(style);

  /* FIXME really HERE ? */
  if (ME_IsSelection(editor))
    ME_DeleteSelection(editor);

  assert(nCursor>=0 && nCursor<editor->nCursors);
  if (len == -1)
    len = lstrlenW(str);
  len = min(len, freeSpace);
  while (len)
  {
    pos = str;
    /* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
    while(pos-str < len && *pos != '\r' && *pos != '\n' && *pos != '\t')
      pos++;
    if (pos-str < len && *pos == '\t') { /* handle tabs */
      WCHAR tab = '\t';

      if (pos!=str)
        ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
    
      ME_InternalInsertTextFromCursor(editor, nCursor, &tab, 1, style, MERF_TAB);
 
      pos++;
      if(pos-str <= len) {
        len -= pos - str;
        str = pos;
        continue;
      }
    }
    if (pos-str < len) {   /* handle EOLs */
      ME_DisplayItem *tp, *end_run;
      ME_Style *tmp_style;
      if (pos!=str)
        ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
      p = &editor->pCursors[nCursor];
      if (p->nOffset) {
        ME_SplitRunSimple(editor, p->pRun, p->nOffset);
        p = &editor->pCursors[nCursor];
      }
      tmp_style = ME_GetInsertStyle(editor, nCursor);
      /* ME_SplitParagraph increases style refcount */
      tp = ME_SplitParagraph(editor, p->pRun, p->pRun->member.run.style);
      p->pRun = ME_FindItemFwd(tp, diRun);
      end_run = ME_FindItemBack(tp, diRun);
      ME_ReleaseStyle(end_run->member.run.style);
      end_run->member.run.style = tmp_style;
      p->nOffset = 0;
      if(pos-str < len && *pos =='\r')
        pos++;
      if(pos-str < len && *pos =='\n')
        pos++;
      if(pos-str <= len) {
        len -= pos - str;
        str = pos;
        continue;
      }
    }
    ME_InternalInsertTextFromCursor(editor, nCursor, str, len, style, 0);
    len = 0;
  }
}