Home

Awesome

MARK

by Ingo Karkat (original version by Yuheng Xie)

DESCRIPTION

This plugin adds mappings and a :Mark command to highlight several words in different colors simultaneously, similar to the built-in 'hlsearch' highlighting of search results and the * star command. For example, when you are browsing a big program file, you could highlight multiple identifiers in parallel. This will make it easier to trace the source code.

This is a continuation of vimscript #1238 by Yuheng Xie, who doesn't maintain his original version anymore and recommends switching to this fork. This plugin offers the following advantages over the original:

SEE ALSO

RELATED WORKS

USAGE

HIGHLIGHTING

<Leader>m               Mark the word under the cursor, similar to the star
                        command. The next free highlight group is used.
                        If already on a mark: Clear the mark, like
                        <Leader>n.
{Visual}<Leader>m       Mark or unmark the visual selection.
{N}<Leader>m            With {N}, mark the word under the cursor with the
                        named highlight group {N}. When that group is not
                        empty, the word is added as an alternative match, so
                        you can highlight multiple words with the same color.
                        When the word is already contained in the list of
                        alternatives, it is removed.

                        When {N} is greater than the number of defined mark
                        groups, a summary of marks is printed. Active mark
                        groups are prefixed with "*" (or "M*" when there are
                        M pattern alternatives), the default next group with
                        ">", the last used search with "/" (like :Marks
                        does). Input the mark group, accept the default with
                        <CR>, or abort with <Esc> or any other key.
                        This way, when unsure about which number represents
                        which color, just use 99<Leader>n and pick the color
                        interactively!

{Visual}[N]<Leader>m    Ditto, based on the visual selection.

[N]<Leader>r            Manually input a regular expression to mark.
{Visual}[N]<Leader>r    Ditto, based on the visual selection.

                        In accordance with the built-in star command,
                        all these mappings use 'ignorecase', but not
                        'smartcase'.

<Leader>n               Clear the mark under the cursor.
                        If not on a mark: Disable all marks, similar to
                        :nohlsearch.
                        Note: Marks that span multiple lines are not detected,
                        so the use of <Leader>n on such a mark will
                        unintentionally disable all marks! Use
                        {Visual}<Leader>r or :Mark {pattern} to clear
                        multi-line marks (or pass [N] if you happen to know
                        the group number).
{N}<Leader>n            Clear the marks represented by highlight group {N}.

:{N}Mark                Clear the marks represented by highlight group {N}.
:[N]Mark[!] [/]{pattern}[/]
                        Mark or unmark {pattern}. Unless [N] is given, the
                        next free highlight group is used for marking.
                        With [N], mark {pattern} with the named highlight
                        group [N]. When that group is not empty, the word is
                        added as an alternative match, so you can highlight
                        multiple words with the same color, unless [!] is
                        given; then, {pattern} overrides the existing mark.
                        When the word is already contained in the list of
                        alternatives, it is removed.
                        For implementation reasons, {pattern} cannot use the
                        'smartcase' setting, only 'ignorecase'.
                        Without [/], only literal whole words are matched.
                        :search-args
:Mark                   Disable all marks, similar to :nohlsearch. Marks
                        will automatically re-enable when a mark is added or
                        removed, or a search for marks is performed.

:MarkClear              Clear all marks. In contrast to disabling marks, the
                        actual mark information is cleared, the next mark will
                        use the first highlight group. This cannot be undone.

:[N]Mark[!] /{pattern}/ as [name]
                        Mark or unmark {pattern}, and give it [name].
:{N}MarkName [name]
                        Give [name] to mark group {N}.
:MarkName!              Clear names for all mark groups.

SEARCHING

[count]*         [count]#
[count]<Leader>* [count]<Leader>#
[count]<Leader>/ [count]<Leader>?
                        Use these six keys to jump to the [count]'th next /
                        previous occurrence of a mark.
                        You could also use Vim's / and ? to search, since the
                        mark patterns are (optionally, see configuration)
                        added to the search history, too.

            Cursor over mark                    Cursor not over mark
 ---------------------------------------------------------------------------
  <Leader>* Jump to the next occurrence of      Jump to the next occurrence of
            current mark, and remember it       "last mark".
            as "last mark".

  <Leader>/ Jump to the next occurrence of      Same as left.
            ANY mark.

   *        If <Leader>* is the most recently   Do Vim's original * command.
            used, do a <Leader>*; otherwise
            (<Leader>/ is the most recently
            used), do a <Leader>/.

                        Note: When the cursor is on a mark, the backwards
                        search does not jump to the beginning of the current
                        mark (like the built-in search), but to the previous
                        mark. The entire mark text is treated as one entity.

                        You can use Vim's jumplist to go back to previous
                        mark matches and the position before a mark search.

If you work with multiple highlight groups and assign special meaning to them
(e.g. group 1 for notable functions, 2 for variables, 3 for includes), you can
use the 1-9 keys on the numerical keypad to jump to occurrences of a
particular highlight group. With the general * and # commands above, you'd
first need to locate a nearby occurrence of the desired highlight group if
it's not the last mark used.

<k1> .. <k9>            Jump to the [count]'th next occurrence of the mark
                        belonging to highlight group 1..9.
<C-k1> .. <C-k9>        Jump to the [count]'th previous occurrence of the mark
                        belonging to highlight group 1..9.
                        Note that these commands only work in GVIM or if your
                        terminal sends different key codes; sadly, most still
                        don't.
                        https://unix.stackexchange.com/questions/552297/make-gnome-terminal-send-correct-numeric-keypad-keycodes-to-vim
                        The "Num Lock" indicator of your keyboard has
                        to be ON; otherwise, the keypad is used for cursor
                        movement. If the keypad doesn't work for you, you can
                        still remap these mappings to alternatives; see below.
Alternatively, you can set up mappings to search in a next / previous used
group, see mark-group-cycle.

[...]
After a stop, retriggering the cascaded search in the same buffer and window
moves to the next used group (you can jump inside the current buffer to choose
a different starting point first). If you instead switch to another window or
buffer, the current mark group continues to be searched (to allow you to
keep searching for the current group in other locations, until those are all
exhausted too).

MARK PERSISTENCE

The marks can be kept and restored across Vim sessions, using the viminfo
file. For this to work, the "!" flag must be part of the 'viminfo' setting:
    set viminfo^=!  " Save and restore global variables.

:MarkLoad               Restore the marks from the previous Vim session. All
                        current marks are discarded.
:MarkLoad {slot}        Restore the marks stored in the named {slot}. All
                        current marks are discarded.

:MarkSave               Save the currently defined marks (or clear the
                        persisted marks if no marks are currently defined) for
                        use in a future Vim session.
:MarkSave {slot}        Save the currently defined marks in the named {slot}.
                        If {slot} is all UPPERCASE, the marks are persisted
                        and can be |:MarkLoad|ed in a future Vim session (to
                        persist without closing Vim, use :wviminfo; an
                        already running Vim session can import marks via
                        :rviminfo followed by :MarkLoad).
                        If {slot} contains lowercase letters, you can just
                        recall within the current session. When no marks are
                        currently defined, the {slot} is cleared.

By default, automatic persistence is enabled (so you don't need to explicitly
:MarkSave), but you have to explicitly load the persisted marks in a new Vim
session via :MarkLoad, to avoid that you accidentally drag along outdated
highlightings from Vim session to session, and be surprised by the arbitrary
highlight groups and occasional appearance of forgotten marks. If you want
just that though and automatically restore any marks, set g:mwAutoLoadMarks.

You can also initialize some marks (even using particular highlight groups) to
static values, e.g. by including this in vimrc:
    runtime plugin/mark.vim
    silent MarkClear
    silent 5Mark foo
    silent 6Mark /bar/
Or you can define custom commands that preset certain marks:
    command -bar MyMarks exe '5Mark! foo' | exe '6Mark! /bar/'
Or a command that adds to the existing marks and then toggles them:
    command -bar ToggleFooBarMarks exe 'Mark foo' | exe 'Mark /bar/'
The following commands help with setting these up:

:MarkYankDefinitions [x]
                        Place definitions for all current marks into the
                        default register / [x], like this:
                            1Mark! /\<foo\>/
                            2Mark! /bar/
                            9Mark! /quux/
:MarkYankDefinitionsOneLiner [x]
                        Like :MarkYankDefinitions, but place all definitions
                        into a single line, like this:
                        exe '1Mark! /\<foo\>/' | exe '2Mark! /bar/' | exe '9Mark! /quux/'
Alternatively, the mark#GetDefinitionCommands(isOneLiner) function can be used
to obtain a List of :Mark commands instead of using a register. With that,
you could for example build a custom alternative to :MarkSave that stores
Marks in separate files (using writefile(), read by :source or even
automatically via a local vimrc plugin) instead of the viminfo file.

MARK INFORMATION

Both mark-highlighting and mark-searching commands print information about
the mark and search pattern, e.g.
        mark-1/\<pattern\>
This is especially useful when you want to add or subtract patterns to a mark
highlight group via [N].

:Marks                  List all mark highlight groups and the search patterns
                        defined for them.
                        The group that will be used for the next :Mark or
                        <Leader>m command (with [N]) is shown with a ">".
                        The last mark used for a search (via <Leader>*) is
                        shown with a "/".

MARK HIGHLIGHTING PALETTES

The plugin comes with three predefined palettes: original, extended, and
maximum. You can dynamically toggle between them, e.g. when you need more
marks or a different set of colors.

:MarkPalette {palette}  Highlight existing and future marks with the colors
                        defined in {palette}. If the new palette contains less
                        mark groups than the current one, the additional marks
                        are lost.
                        You can use :command-completion for {palette}.

See g:mwDefaultHighlightingPalette for how to change the default palette,
and mark-palette-define for how to add your own custom palettes.

INSTALLATION

The code is hosted in a Git repo at https://github.com/inkarkat/vim-mark You can use your favorite plugin manager, or "git clone" into a directory used for Vim packages. Releases are on the "stable" branch, the latest unstable development snapshot on "master".

This script is also packaged as a vimball. If you have the "gunzip" decompressor in your PATH, simply edit the *.vmb.gz package in Vim; otherwise, decompress the archive first, e.g. using WinZip. Inside Vim, install by sourcing the vimball or via the :UseVimball command.

vim mark*.vmb.gz
:so %

To uninstall, use the :RmVimball command.

DEPENDENCIES

CONFIGURATION

For a permanent configuration, put the following commands into your vimrc.

This plugin defines 6 mark groups:

    1: Cyan  2:Green  3:Yellow  4:Red  5:Magenta  6:Blue

Higher numbers always take precedence and are displayed above lower ones.

Especially if you use GVIM, you can switch to a richer palette of up to 18 colors:

let g:mwDefaultHighlightingPalette = 'extended'

Or, if you have both good eyes and display, you can try a palette that defines 27, 58, or even 77 colors, depending on the number of available colors:

let g:mwDefaultHighlightingPalette = 'maximum'

Note: This only works for built-in palettes and those that you define prior to running the plugin. If you extend the built-ins after plugin initialization (mark-palette-define), use :MarkPalette instead.

If you like the additional colors, but don't need that many of them, restrict their number via:

    let g:mwDefaultHighlightingNum = 9

If none of the default highlightings suits you, define your own colors in your vimrc file (or anywhere before this plugin is sourced, but after any :colorscheme), in the following form (where N = 1..):

highlight MarkWordN ctermbg=Cyan ctermfg=Black guibg=#8CCBEA guifg=Black

You can also use this form to redefine only some of the default highlightings. If you want to avoid losing the highlightings on :colorscheme commands, you need to re-apply your highlights on the ColorScheme event, similar to how this plugin does. Or you define the palette not via :highlight commands, but use the plugin's infrastructure:

let g:mwDefaultHighlightingPalette = [
\   { 'ctermbg':'Cyan', 'ctermfg':'Black', 'guibg':'#8CCBEA', 'guifg':'Black' },
\   ...
\]

If you want to switch multiple palettes during runtime, you need to define them as proper palettes. a) To add your palette to the existing ones, do this after the default palette has been defined (e.g. in ~/.vim/after/plugin/mark.vim):

if ! exists('g:mwPalettes') " (Optional) guard if the plugin isn't properly installed.
    finish
endif

let g:mwPalettes['mypalette'] = [
\   { 'ctermbg':'Cyan', 'ctermfg':'Black', 'guibg':'#8CCBEA', 'guifg':'Black' },
\   ...
\]
let g:mwPalettes['other'] = [ ... ]

" Make it the default; you cannot use g:mwDefaultHighlightingPalette
here, as the Mark plugin has already been initialized:
MarkPalette mypalette

b) Alternatively, you can completely override all built-in palettes in your vimrc:

let g:mwPalettes = {
\   'mypalette': [
\       { 'ctermbg':'Cyan', 'ctermfg':'Black', 'guibg':'#8CCBEA', 'guifg':'Black' },
\       ...
\   ]
\}

" Make it the default:
let g:mwDefaultHighlightingPalette = 'mypalette'

The search type highlighting (in the search message) can be changed via:

highlight link SearchSpecialSearchType MoreMsg

By default, any marked words are also added to the search (/) and input (@) history; if you don't want that, remove the corresponding symbols from:

let g:mwHistAdd = '/@'

To enable the automatic restore of marks from a previous Vim session:

let g:mwAutoLoadMarks = 1

To turn off the automatic persistence of marks across Vim sessions:

let g:mwAutoSaveMarks = 0

You can still explicitly save marks via :MarkSave.

If you have set 'ignorecase', but want marks to be case-insensitive, you can override the default behavior of using 'ignorecase' by setting:

    let g:mwIgnoreCase = 0

To exclude some tab pages, windows, or buffers / filetypes from showing mark highlightings (you can still "blindly" navigate to marks in there with the corresponding mappings), you can define a List of expressions or Funcrefs that are evaluated in every window; if one returns 1, the window will not show marks.

" Don't mark temp files, Python filetype, and scratch files as defined by
" a custom function.
let g:mwExclusionPredicates =
\   ['expand("%:p") =~# "/tmp"', '&filetype == "python", function('ExcludeScratchFiles')]

By default, tab pages / windows / buffers that have t:nomarks / w:nomarks / b:nomarks with a true value are excluded. Therefore, to suppress mark highlighting in a buffer, you can simply

:let b:nomarks = 1

If the predicate changes after a window has already been visible, you can update the mark highlighting by either:

This plugin uses matchadd() for the highlightings. Each mark group has its own priority, with higher group values having higher priority; i.e. going "on top". The maximum priority (used for the last defined mark group) can be changed via:

let g:mwMaxMatchPriority = -10

For example when another plugin or customization also uses matches and you would like to change their relative priorities. The default is negative to step back behind the default search highlighting.

If you want no or only a few of the available mappings, you can completely turn off the creation of the default mappings by defining:

:let g:mw_no_mappings = 1

This saves you from mapping dummy keys to all unwanted mapping targets.

You can use different mappings by mapping to the <Plug>Mark... mappings (use ":map <Plug>Mark" to list them all) before this plugin is sourced.

There are no default mappings for toggling all marks and for the :MarkClear command, but you can define some yourself:

nmap <Leader>M <Plug>MarkToggle
nmap <Leader>N <Plug>MarkAllClear

As the latter is irreversible, there's also an alternative with an additional confirmation:

nmap <Leader>N <Plug>MarkConfirmAllClear

To remove the default overriding of * and #, use:

nmap <Plug>IgnoreMarkSearchNext <Plug>MarkSearchNext
nmap <Plug>IgnoreMarkSearchPrev <Plug>MarkSearchPrev

If you don't want the * and # mappings remember the last search type and instead always search for the next occurrence of the current mark, with a fallback to Vim's original * command, use:

nmap * <Plug>MarkSearchOrCurNext
nmap # <Plug>MarkSearchOrCurPrev

Or for search for the next occurrence of any mark with fallback to *:

nmap * <Plug>MarkSearchOrAnyNext
nmap # <Plug>MarkSearchOrAnyPrev

Mark searches could also be combined with the built-in search. This mapping overloads the default n|/|N commands to search for any mark if there is any mark defined and marks are enabled, and fall back to the default search if not:

nmap n <Plug>MarkSearchAnyOrDefaultNext
nmap N <Plug>MarkSearchAnyOrDefaultPrev

The search mappings (*, #, etc.) interpret [count] as the number of occurrences to jump over. If you don't want to use the separate mark-keypad-searching mappings, and rather want [count] select the highlight group to target (and you can live with jumps restricted to the very next match), (re-)define to these mapping targets:

nmap * <Plug>MarkSearchGroupNext
nmap # <Plug>MarkSearchGroupPrev

You can remap the direct group searches (by default via the keypad 1-9 keys):

nmap <Leader>1  <Plug>MarkSearchGroup1Next
nmap <Leader>!  <Plug>MarkSearchGroup1Prev

If you need more / less groups, this can be configured via:

let g:mwDirectGroupJumpMappingNum = 20

Set to 0 to completely turn off the keypad mappings. This is easier than remapping all <Plug>-mappings.

As an alternative to the direct group searches, you can also define mappings that search a next / previous used group:

nmap <Leader>+* <Plug>MarkSearchUsedGroupNext
nmap <Leader>-* <Plug>MarkSearchUsedGroupPrev

Some people like to create a mark based on the visual selection, like v_<Leader>m, but have whitespace in the selection match any whitespace when searching (searching for "hello world" will also find "hello<Tab>world" as well as "hello" at the end of a line, with "world" at the start of the next line). The Vim Tips Wiki describes such a setup for the built-in search at http://vim.wikia.com/wiki/Search_for_visually_selected_text You can achieve the same with the Mark plugin through the <Plug>MarkIWhiteSet mapping target: Using this, you can assign a new visual mode mapping <Leader>*

xmap <Leader>* <Plug>MarkIWhiteSet

or override the default v_<Leader>m mapping, in case you always want this behavior:

vmap <Plug>IgnoreMarkSet <Plug>MarkSet
xmap <Leader>m <Plug>MarkIWhiteSet

INTEGRATION

The following functions offer (read-only) access to the script's internals:

LIMITATIONS

CONTRIBUTING

Report any bugs, send patches, or suggest features via the issue tracker at https://github.com/inkarkat/vim-mark/issues or email (address below).

HISTORY

3.2.1 RELEASEME
3.2.0 15-Feb-2022

You need to update to ingo-library (vimscript #4433) version 1.043!

3.1.1 03-Aug-2020

You need to update to ingo-library (vimscript #4433) version 1.042!

3.1.0 23-Mar-2019

You need to update to ingo-library (vimscript #4433) version 1.036!

3.0.0 18-Sep-2017

You need to separately install ingo-library (vimscript #4433) version 1.020 (or higher)!

2.8.5 29-Oct-2014
2.8.4 19-Jun-2014
2.8.3 23-May-2014
2.8.2 16-Dec-2013
2.8.1 22-Nov-2013
2.8.0 01-Jun-2013
2.7.2 15-Oct-2012
2.7.1 14-Sep-2012
2.7.0 04-Jul-2012
2.6.5 24-Jun-2012
2.6.4 23-Apr-2012
2.6.3 27-Mar-2012
2.6.2 26-Mar-2012

PLEASE UPDATE THE vnoremap <Plug>MarkWhitespaceIndifferent DEFINITION

2.6.1 23-Mar-2012
2.6.0 22-Mar-2012
2.5.3 02-Mar-2012
2.5.2 09-Nov-2011
2.5.1 17-May-2011
2.5.0 07-May-2011
2.4.4 18-Apr-2011
2.4.3 16-Apr-2011
2.4.2 14-Jan-2011 (unreleased)
2.4.1 13-Jan-2011
2.4.0 13-Jul-2010
2.3.3 19-Feb-2010
2.3.2 17-Nov-2009
2.3.1 06-Jul-2009
2.3.0 04-Jul-2009
2.2.0 02-Jul-2009
2.1.0 06-Jun-2009
2.0.0 01-Jun-2009
1.6.1 31-May-2009
1.5.0 01-Sep-2008
1.1.8-g 25-Apr-2008
1.1.2 22-Mar-2005

Copyright: (C) 2008-2023 Ingo Karkat - (C) 2005-2008 Yuheng Xie - The VIM LICENSE applies to this plugin.

Maintainer: Ingo Karkat <ingo@karkat.de>