2

I use gF a good amount when getting to the bottom of compilation errors in different tech stacks. With Dart/Flutter, I'm getting the error messages in the following format:

lib/main.dart:58:34: Error: 'FooStates' isn't a type.
          ChangeNotifierProvider<FooStates>(
                                 ^^^^^^^^^
Try again after fixing the above error(s).

placing the cursor on the path and running gF results in a E447: Cannot find file "lib/main.dart:58:34" in path error, which is to be expected. The help says:

[count]gF       Same as "gf", except if a number follows the file
            name, then the cursor is positioned on that line in
            the file.
            The file name and the number must be separated by a
            non-filename (see 'isfname') and non-numeric
            character. " line " is also recognized, like it is
            used in the output of `:verbose command UserCmd`
            White space between the filename, the separator and
            the number are ignored.
            Examples:
                eval.c:10 ~
                eval.c @ 20 ~
                eval.c (30) ~
                eval.c 40 ~

From what I can understand I can add a "filter" to the strings passed to gF, so that when no file is matched, a substitution is performed and the modified string is matched again against the files in the workspace.

I can't seem to get the correct invocation for it though. Here's what I tried:

autocmd FileType log setlocal includeexpr=substitute(v:fname, ':\\d+$', '', '')

This spits out the following error when trying to open a log type buffer:

Error detected while processing BufEnter Autocommands for "__FLUTTER_DEV_LOG__":                                                                                                                                                                                                                 
E5108: Error executing lua ...vim/plugged/flutter-tools.nvim/lua/flutter-tools/log.lua:104: Vim(setlocal):E518: Unknown option: ':\\d+$', 

When I skip the per-filetype logic and add something like this to init.vim:

:set includeexpr=smagic(v:fname,':[0-9]+$','','g')

it just doesn't seem to have any effect on gF - the file.ext:line:column format is still not recognized

2
  • 2
    The Unknown option: ':\\d+$', part is because you can't have spaces in a :set or :setlocal command. If you need spaces in the value of an option, you need to backslash escape them. (This gets very tricky in an autocmd, so I won't even try to guess what the right syntax for it would be.)
    – filbranden
    Dec 16, 2021 at 13:26
  • Using let &l:includeexpr = … is thus much nicer, but you may have two levels of strings :)
    – D. Ben Knoble
    Dec 16, 2021 at 16:29

1 Answer 1

2

Since @filbranden have a good answer in comments for the Unknown option: ':\\d+$', part. I'm going to do my best to answer the second one.

placing the cursor on the path and running gF results in a E447: Cannot find file "lib/main.dart:58:34" in path error

This error gives us a clue that the editor try to open a file, which path was "lib/main.dart:58:34". Let's try to ask the problem to Neovim by the following command.

:echo substitute("lib/main.dart:58:34", ':\\d+$', '', '')

As you can see. The result would be lib/main.dart:58:34. From here, We know it's likely a pattern matching problem.

The options.txt says

                                                        *option-backslash*
To include white space in a string option value it has to be preceded with a
backslash.  To include a backslash you have to use two.  Effectively this
means that the number of backslashes in an option value is halved (rounded
down).
A few examples: >
   :set tags=tags\ /usr/tags        results in "tags /usr/tags"
   :set tags=tags\\,file        results in "tags\,file"
   :set tags=tags\\\ file       results in "tags\ file"

and take a look at the section of Multi Items:

     'magic' 'nomagic'  matches of the preceding atom
/star   *       \*      0 or more       as many as possible
/\+     \+      \+      1 or more       as many as possible
/\=     \=      \=      0 or 1          as many as possible

So we should move duplicated backslash from \d to + as the following command. Because we don't put the pattern in :set for testing.

:echo substitute("lib/main.dart:58:34", ':\d\+$', '', '')

The result turns to lib/main.dart:58. Again, it won't work. Since the output doesn't look like a good file name.

it just doesn't seem to have any effect on gF - the file.ext:line:column format is still not recognized

Let's write a pattern string against the format.

To change includeexpr with fewer characters as possible:

It would be :set includeexpr=substitute(v:fname,':\\d\\+','','g')

Here is my version. It's more readable (No escapes). Enjoy!

:set includeexpr=substitute(v:fname,'.dart:.*','.dart','')

UPDATE: If you can't go to the line number automatically after jumping. You should check the option isfname and remove colon if necessary. There is no need to set includexpr, Leave it empty should works, since the format file.ext:line:column is supported natively in Vim.

set isfname-=:
2
  • But your version gets rid of the line number, doesn't it? The OP wanted to keep the line number, hence gF. It's only the column that needs removed.
    – D. Ben Knoble
    Apr 19 at 19:52
  • @D.BenKnoble ok, I got the point and also update the answer for it.
    – Gasol
    Apr 20 at 2:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.