Hi!
I've been wanting to have some kind of word-completion mechanism in LyX
(something like C-p in vim or M-/ in emacs). The only mention of this
that I found was in the unanswered questions section in the FAQ
(http://wiki.lyx.org/FAQ/Unanswered#toc2), or on the Complaints page in
the LyX wiki, so I gather that it doesn't exist yet. Since I have a
little spare time on my hands at the moment, I thought maybe I'd try
writing a patch. (More on this later...)
While trying to get my bearings in the code, I noticed that there was a
stub for a transpose function (LFUN_TRANSPOSE_CHARS), so I thought that
writing that function would be a good exercise for getting familiar with
the code. Attached is a patch (against 1.4.3) which adds the transpose
functionality. (Of course, to make it at all useful, it really needs to
be bound to a key --- I bound it to C-t for myself, but I didn't include
that in the patch, as C-t is already taken.)
A few comments about the patch:
* It took me a while to figure this out, but I was finally able to get
it so that undo sees the transposition as a single atomic action;
* the same goes for making sure that the transposition *is* tracked by
the change-tracking mechanism.
* There is still a problem with a transposition which takes place on
the border between two languages (at least, I have the problem when
moving between English and Hebrew, which is RTL). There's no real reason
to ever want to transpose such a case, so the patch could be committed
as is; on the other hand, if someone can help me out with fixing this,
that would be great. (What I need to know is, how do I identify the
transition between languages/directions? I'd just as soon just cancel
the action if I recognize that I'm on such a border.)
* I have a feeling that what I currently do for checking that both
characters are "regular text" (and not an inset, for example), is not
complete; however, it seems to work. Again, if someone could help me out
with how better to check for this condition, I'll fix the code if necessary.
Is there any documentation for developers? Specifically, something which
explains in general how the document/buffer is stored in memory (i.e.:
how are insets, language changes, etc. represented)?
Finally, back to word-completion: I've started working on that, but the
main problem I've run into is preserving state between consecutive
invocations. For example, let's say C-p is bound to this function. So
the first time I call C-p, the word which the cursor is at is completed.
The problem is, if I immediately (i.e., before moving the cursor or
doing anything else in the document) press C-p again, I would like to
get the next possible completion. But (a) how do I know that this is not
the first call to the completion function, and (b) is there any way to
keep track of the list of possible completion that I already found the
first time around, so that I don't need to go through the whole buffer
again?
I'd appreciate any thoughts or suggestions on this (all of the above).
Thanks,
Dov
Index: src/lyxtext.h
===================================================================
--- src/lyxtext.h (revision 15158)
+++ src/lyxtext.h (working copy)
@@ -244,6 +244,8 @@
};
/// Change the case of the word at cursor position.
void changeCase(LCursor & cur, TextCase action);
+ /// Transpose characters at cursor position.
+ void charsTranspose(LCursor & cur);
/** the DTP switches for paragraphs. LyX will store the top settings
always in the first physical paragraph, the bottom settings in the
Index: src/text3.C
===================================================================
--- src/text3.C (revision 15158)
+++ src/text3.C (working copy)
@@ -728,7 +728,7 @@
break;
case LFUN_TRANSPOSE_CHARS:
- recordUndo(cur);
+ charsTranspose(cur);
break;
case LFUN_PASTE:
Index: src/text.C
===================================================================
--- src/text.C (revision 15158)
+++ src/text.C (working copy)
@@ -1585,6 +1585,55 @@
}
+// Transposes the character at the cursor with the one before it.
+void LyXText::charsTranspose(LCursor & cur)
+{
+ BOOST_ASSERT(this == cur.text());
+ CursorSlice from;
+
+ from = cur.top();
+
+ pos_type pos = from.pos();
+ pit_type par = from.pit();
+
+ // If cursor is at end of paragraph, transpose last two characters.
+ if (pos == cur.lastpos()) {
+ --pos;
+ }
+
+ // If there is no previous character in paragraph, don't do anything.
+ if (pos < 1) {
+ return;
+ }
+
+ --pos; // Just more convenient to work from the first character.
+
+ // Don't do anything if one of the "characters" is not regular text.
+ if (pars_[par].isInset(pos) || pars_[par].isInset(pos + 1))
+ return;
+
+ // Build the transposed string.
+ char transposed[3];
+ transposed[0] = pars_[par].getChar(pos + 1);
+ transposed[1] = pars_[par].getChar(pos);
+ transposed[2] = '\0';
+
+ // And finally, we are ready to perform the transposition.
+ // We use erase() and insert(), which take care of tracking the
+ // change.
+ recordUndoSelection(cur);
+
+ LyXFont const font =
+ pars_[par].getFontSettings(cur.buffer().params(), pos);
+
+ cur.paragraph().erase(pos, pos + 2);
+ cur.paragraph().insert(pos, transposed, font);
+
+ // After the transposition, move cursor one position forward.
+ cursorRight(cur);
+}
+
+
bool LyXText::Delete(LCursor & cur)
{
BOOST_ASSERT(this == cur.text());