Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do something in a function based on the character under the cursor in Vim?

I’m writing a function that edits a certain environment in LaTeX.

The environment basically looks like this:

\begin{quicktikz}
    ...some stuff...
\end{quicktikz}

or like this:

\begin*{quicktikz}
    ...some stuff...
\end{quicktikz}

I want to write a function that toggles between the two, when called from within the environment. Since my Vim knowledge ain’t all that, I’m coming up with a simple solution:

  1. Get cursor position with let save_cursor=getpos(".").
  2. Backward search for \begin{quicktikz} using: ?\\begin{quicktikz}\|\\begin\*{quicktikz}.
  3. Search for the { and move left using: normal 0f{h.
  4. Check if the item under cursor equals *:
    • if it does, do normal x;
    • if it doesn’t, do normal a*<esc>.
  5. Restore cursor position using call setpos('.',save_cursor).

I know how to do all of this except for step 3. How can I check if the char under the cursor equals to * or not?

If you know a better way of doing this, sharing this would be welcome.

like image 564
romeovs Avatar asked Sep 26 '11 20:09

romeovs


2 Answers

I think the easiest way to retrieve the char under cursor is:

getline(".")[col(".")-1]

Alternatively, you can do it with strpart()

strpart(getline("."), col(".")-1, 1)

The first expression first calls the function getline() passing "." as argument which means the line where the cursor is positioned will be returned. Then we use the so called expr8 or expr-[] (see the help) to retrieve a single character. The number passed comes from another function, col() which returns the current cursor column. As indexes start in 0, one is subtracted.

You can use it like

if getline(".")[col(".")-1] == '*'
        ...
like image 58
sidyll Avatar answered Oct 08 '22 14:10

sidyll


Let me propose an alternative implementation of the technique you describe.

:?\\begin\>\zs\*\=?s//\='*'[submatch(0)!='']/|norm!``

The above command consists of two separate commands chained with | (see :help :bar) in one line. The first one is a substitution (see :help :s) performed for each line in the specified range,

?\\begin\>\zs\*\=?

According to the range syntax (see :help :range), this range specifies the only line, that is the previous line where the \\begin\>\zs\*\= pattern matches the word begin preceded with a backslash and followed by by optional star character.1 The \zs atom between parts of the pattern matching \begin and *, sets the start of the match there. So, the match of the whole pattern is either empty or contains single star character. This is not necessary for specifying a line in the range, it is useful for reusing the same pattern later in the :substitute command, where only that star character or its empty place should be replaced. For details about the pattern's syntax see :help /\>, :help /\=, :help /\zs.

The substitution itself,

s//\='*'[submatch(0)!='']/

replaces the first occurrence of the last search pattern (which is set by the backward search in the range) with a string to which the expression '*'[submatch(0)!=''] evaluates (see :help sub-replace-\=). As the pattern matches only an empty string or a star character, the subexpression submatch(0)!='' evaluates to zero if there is no star after \begin, or to one otherwise. Zero subscript from the string '*' results in a substring containing the first character of that one-character string. Index one is equal to the length of the string, therefore subscript results in an empty string. Thus, when there is a star after \begin, it gets replaced with an empty string, when a star is not present, zero-width interval just after \begin is substituted with *.

The second command,

:norm!``

takes advantage of the fact that :substitute command stores the current cursor position before it actually starts replacement. The `` movement command jumps back to the position before the latest jump (which occurs in the aforementioned substitution command) restoring position of the cursor.2


1 Be careful with search, since in ranges, as usual, it wraps around the end of file, when the wrapscan option is enabled (it is turned on by default).

2 Do not confuse `` with the '' command which moves the cursor to the first non-blank character in the line of the location before the latest jump.

like image 40
ib. Avatar answered Oct 08 '22 14:10

ib.