Lexical Navigation

Yannick Gingras ygingras at ygingras.net
Mon Feb 7 06:29:10 GMT 2022

In Lisp, Emacs offers a rather interesting code navigation. There are
basically only 3 short-cuts that provide most of what anyone needs:
- go to outer scope;
- go to next item with same scope;
- go to previous item with same scope.

There might be go to inner scope, but after going outer scope, it's
typically just one key stroke away to go one scope down: right arrow.

Take the following example (not any real Lisp dialect):
(def foo (a b c)
    (for (i x (enumerate (range b c))
        (ifeq (a x)
            (return i)))))
What the code does is not really important, but a Python version of it
would look line this:
def foo(a, b, c):
    for i, x in enumerate(range(b, c)):
        if a == x:
            return i
Besides being a great example of how mind twisting Lisp can be, it
illustrate beautifully how one could take advantage of lexcical
navidation. Say I just finished typing the "enumerate" clause and I
want to add a default return if we don't find any `x` that is equal to
`a`. I would go "outer scope" 3 times, "then next same scope" once. It
would put me inside that big ugly series of closing parens: ")))))",
right before the last one. I can then type Return and add my default
return clause: (return nil). That's like "return None" in Python or
"return null" in great many language.

Kate already offers something really close to this, but not the whole
solution. There is "go to matching bracket" and "previous and next
matching intent", which is just like go to next item with same scope in
Python. It's almost there! Wouldn't it be cool to be able to say: "I'm
done with this for, I just want to add something right after it"? To do
that, one would need "go to outer scope", which neither exists for
brackets nor for indents, and a small variation to "move to to next
indent" that stops at the end of the current intent rather than
entering the next block and finding the first statement that has the
same indent.

Of course, a general implementation that works for many languages is
going to be a lot more complicated than the Lisp one, which has the
benefit of only having to match parentheses, but I feel like this is a
very natural way way to move around code that might justify the
implementation complexity.

I'm also not volunteering to implement this, at least not the whole
thing. I looked at the script API, and it would be doable there, but
kind of hard because it's all character based and most of the semantic
is not passed to the script. I think that the LSP Code Actions protocol
would be the most logical way to do this since inside the LSP, there is
a lot of semantic info available. It looks pretty heavy, however, so
I'm not sure this is where a proof of concept should go. The external
tools plugin however supports everything that is needed. If I can call
a Python script, I can easily get the semeantic info back (for Python
code). I would just need a way to pass back to Kate where to move the
cursor as a response.

Let me end with two unrealated questions:
- does that sound like a way to move around code that you would like to
- is there any chance that the external tools plugin would allow me to
move the cursor in a nearby future?

Sorry for the long message. I could not find a better way to summerize
my thoughts.

Yannick Gingras

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: This is a digitally signed message part
URL: <http://mail.kde.org/pipermail/kwrite-devel/attachments/20220206/f6fc6bfa/attachment.sig>

More information about the KWrite-Devel mailing list