The shebang line has an annoying background color, how to change it to have the same color of comments. This is a Haskell file. enter image description here

  • Does this shell command help $ echo "syn match hsLineComment '^#\!/usr/bin/env stack$'" >>~/.vim/after/syntax/haskell.vim? – user938271 Dec 12 '18 at 12:04
  • The command does not work, it gives an error bash: !/usr/bin/env: event not found; but I have added the line syn match hsLineComment '^#!/usr/bin/env stack$' in ~/.vim/after/syntax/haskell.vim and It does work and solves my problem. could you add a full answer with some explaining to accept your answer, please. – Taha Magdy Dec 12 '18 at 12:10

The shebang line is considered as an error by the default haskell syntax plugin ($VIMRUNTIME/syntax/haskell.vim), and as a result highlighted by the syntax group cError.

You can customize the behavior of the haskell syntax plugin by writing additional statements inside the file ~/.vim/after/syntax/haskell.vim. For example, you could write:

syn match hsLineComment '^#!/usr/bin/env stack$'

This statement tells Vim that whenever it finds a line matching the regex:

^#!/usr/bin/env stack$

It should highlight it with the syntax group hsLineComment. The latter is the syntax group used to highlight the comment that was written below your shebang line in your picture. You may need to tweak the regex to make it more permissive if you want to highlight other kinds of shebang lines.

If you need to find the syntax group highlighting the text under your cursor, you can use this mapping:

nno  <silent>  !s  :<c-u>call <sid>print_syntax_group_stack(v:count)<cr>

fu! s:print_syntax_group_stack(count) abort
    if a:count
        let name = get(s:get_syntax_group_stack(), a:count-1, '')
        if !empty(name)
            exe 'syntax list '.name
        echo join(s:get_syntax_group_stack())

fu! s:get_syntax_group_stack()
    return reverse(map(synstack(line('.'), col('.')), {i,v -> synIDattr(v, 'name')}))

To use it, you need to press !s on the text you're interested in. For example, if you press !s while your cursor is on the comment shown in your picture, Vim should print hsLineComment on the command line.

In this case, there is only one syntax group. But sometimes, there may be several (a stack of syntax groups). If that happens, they will all be printed on the command line from the innermost group to the outermost one.

You may get additional information about a syntax group printed on the command line, by prefixing !s with a count. For example, if you want more information about the first syntax group in the stack, you could press 1!s. For the haskell comment, Vim would print:

--- Syntax items ---
hsLineComment  xxx match "---*\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$"  contains=@Spell
                   links to hsComment

This tells you that:

  • the hsLineComment syntax group contains only 1 item, matching the regex ---*\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$
  • it may contain any item from a syntax group in the cluster @Spell
  • it's highlighted by the highlight group hsComment

hsComment is linked to the highlight group Comment in $VIMRUNTIME/syntax/haskell.vim, which is confirmed by the output of :verb hi hsComment:

:verb hi hsComment

    hsComment      xxx links to Comment
            Last set from /usr/local/share/vim/vim81/syntax/haskell.vim:155

If you have other issues with the default haskell syntax plugin, there may be a global variable which you could set in your vimrc. See :h ft-haskell-syntax for more information.

The command does not work, it gives an error bash: !/usr/bin/env: event not found

I think that was because bash processes the ! character as the beginning of an event designator (see $ man bash, and look for the section HISTORY EXPANSION and the subsection Event Designators). So, it tried to expand !/usr/bin/env into the previous command in the history beginning with the string /usr/bin/env.

This command would probably have avoided the issue:

$ cat <<'EOF' >~/.vim/after/syntax/haskell.vim
syn match hsLineComment '^#!/usr/bin/env stack$'


$ echo 'syn match hsLineComment +^#!/usr/bin/env stack$+' >~/.vim/after/syntax/haskell.vim

You don't have to use a single quote to surround the pattern of a regex. See :h 44.3:

The part at the end is a pattern, like it's used for searching. The // is used to surround the pattern (like how it's done in a ":substitute" command). You can use any other character, like a plus or a quote.

In the last command, + is used because it allows you to use only single quotes around the argument passed to $ echo. Single quotes, contrary to double quotes, suppress the shell history expansion. And since the + character is not in the regex you don't have to escape it (which would make the regex a little less readable).

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.