Git Product home page Git Product logo

compile-mode.nvim's Introduction

Introduction

compile-mode.nvim is a Neovim plugin which emulates the features of Emacs' Compilation Mode. It allows you to run commands which are output into a special buffer, and then rerun that command over and over again as much as you need. See Emacs Compilation Mode for more details.

Installation

Use your favorite plugin manager. compile-mode.nvim depends on plenary.nvim and on baleia.nvim (unless the no_baleia_support option is set).

Here's an example of a Lazy config for compile-mode.nvim:

return {
  "ej-shafran/compile-mode.nvim",
  branch = "latest",
  -- or a specific version:
  -- tag = "v2.0.0"
  dependencies = {
    "nvim-lua/plenary.nvim",
    { "m00qek/baleia.nvim", tag = "v1.3.0" },
  },
  opts = {
    -- you can disable colors by uncommenting this line
    -- no_baleia_support = true,
    default_command = "npm run build"
  }
}

Compilation buffer

The compilation buffer is the buffer into which the output of compilation commands is placed. By default, its name is "*compilation*" (though this can be configured using the buffer_name option). Its filetype is compilation - this can be used to setup :h autocmds (and thus custom keymaps and the like).

After a command has been run, the buffer's output will contain:

  • the "default directory" - i.e., the current working directory from which the command was run
  • the time at which compilation started
  • the compilation command which was executed
  • the output (stdout and stderr) of the command
  • the exit status of the command (a command can exit successfully, abnormally, or by interruption) and when it occurred

If a compilation command is running and another one is triggered, the first command is terminated (using :h jobstop) and this interruption is reported in the compilation buffer. Then, after a tiny delay, the compilation buffer is cleared and the new command starts running.

The compilation buffer has a few local commands and keymaps. The local commands are :CompileGotoError and :CompileInterrupt, mapped to <CR> and <C-c> respectively. Additionally, q is mapped to <CMD>q<CR> to allow for easy closing of the compilation buffer.

The compilation buffer is deleted automatically when Neovim would be closed, so unsaved changes don't get in the way.

Errors

The compilation buffer is checked for errors in real-time, which can then be navigated between using CompileGotoError, NextError and PrevError.

Errors are defined using the error_regexp_table option. Each field in the table consists of a key (the name of the error's source, used for debug information) and a table value. This table has the following keys:

  • {regex} (string) a Vim regex which captures the error and the relevant capture groups; if this regex matches a line an error is determined to be on that line
  • {filename} (integer) the capture group number for the error's filename (capture groups start at 1)
  • {row} (integer|[integer, integer]) either the capture group for the row on which the error occurred, or capture groups for the start and end of the row range in which the error occurred (optional)
  • {col} (integer|[integer, integer]) either the capture group for the column on which the error occurred, or the capture groups for the start and end of the column range in which the error occurred (optional)
  • {type} (level|[integer,integer?]) either an error type (INFO, WARNING, or ERROR, taken from require("compile-mode").level) or a tuple of capture groups (optional, default ERROR)
    • If capture groups are provided and the first capture group is matched, the error is considered of type WARNING. If the second capture group matched, the error is considered to be of type INFO.

Note: a type alias - RegexpMatcher - is available for the values of error_regexp_table

For example, to add TypeScript errors:

require("compile-mode").setup({
    error_regexp_table = {
      typescript = {
	-- TypeScript errors take the form
	-- "path/to/error-file.ts(13,23): error TS22: etc."
        regex = "^\\(.\\+\\)(\\([1-9][0-9]*\\),\\([1-9][0-9]*\\)): error TS[1-9][0-9]*:",
        filename = 1,
        row = 2,
        col = 3,
      }
    }
})
`error_regexp_table` default The default for `error_regexp_table` is:
error_regexp_table = {
	absoft = {
		regex = '^\\%([Ee]rror on \\|[Ww]arning on\\( \\)\\)\\?[Ll]ine[ 	]\\+\\([0-9]\\+\\)[ 	]\\+of[ 	]\\+"\\?\\([a-zA-Z]\\?:\\?[^":\n]\\+\\)"\\?:',
		filename = 3,
		row = 2,
		type = { 1 },
	},
	ada = {
		regex = "\\(warning: .*\\)\\? at \\([^ \n]\\+\\):\\([0-9]\\+\\)$",
		filename = 2,
		row = 3,
		type = { 1 },
	},
	aix = {
		regex = " in line \\([0-9]\\+\\) of file \\([^ \n]\\+[^. \n]\\)\\.\\? ",
		filename = 2,
		row = 1,
	},
	ant = {
		regex = "^[ 	]*\\%(\\[[^] \n]\\+\\][ 	]*\\)\\{1,2\\}\\(\\%([A-Za-z]:\\)\\?[^: \n]\\+\\):\\([0-9]\\+\\):\\%(\\([0-9]\\+\\):\\([0-9]\\+\\):\\([0-9]\\+\\):\\)\\?\\( warning\\)\\?",
		filename = 1,
		row = { 2, 4 },
		col = { 3, 5 },
		type = { 6 },
	},
	bash = {
		regex = "^\\([^: \n	]\\+\\): line \\([0-9]\\+\\):",
		filename = 1,
		row = 2,
	},
	borland = {
		regex = "^\\%(Error\\|Warnin\\(g\\)\\) \\%([FEW][0-9]\\+ \\)\\?\\([a-zA-Z]\\?:\\?[^:( 	\n]\\+\\) \\([0-9]\\+\\)\\%([) 	]\\|:[^0-9\n]\\)",
		filename = 2,
		row = 3,
		type = { 1 },
	},
	python_tracebacks_and_caml = {
		regex = '^[ 	]*File \\("\\?\\)\\([^," \n	<>]\\+\\)\\1, lines\\? \\([0-9]\\+\\)-\\?\\([0-9]\\+\\)\\?\\%($\\|,\\%( characters\\? \\([0-9]\\+\\)-\\?\\([0-9]\\+\\)\\?:\\)\\?\\([ \n]Warning\\%( [0-9]\\+\\)\\?:\\)\\?\\)',
		filename = 2,
		row = { 3, 4 },
		col = { 5, 6 },
		type = { 7 },
	},
	cmake = {
		regex = "^CMake \\%(Error\\|\\(Warning\\)\\) at \\(.*\\):\\([1-9][0-9]*\\) ([^)]\\+):$",
		filename = 2,
		row = 3,
		type = { 1 },
	},
	cmake_info = {
		regex = "^  \\%( \\*\\)\\?\\(.*\\):\\([1-9][0-9]*\\) ([^)]\\+)$",
		filename = 1,
		row = 2,
		type = M.level.INFO,
	},
	comma = {
		regex = '^"\\([^," \n	]\\+\\)", line \\([0-9]\\+\\)\\%([(. pos]\\+\\([0-9]\\+\\))\\?\\)\\?[:.,; (-]\\( warning:\\|[-0-9 ]*(W)\\)\\?',
		filename = 1,
		row = 2,
		col = 3,
		type = { 4 },
	},
	cucumber = {
		regex = "\\%(^cucumber\\%( -p [^[:space:]]\\+\\)\\?\\|#\\)\\%( \\)\\([^(].*\\):\\([1-9][0-9]*\\)",
		filename = 1,
		row = 2,
	},
	msft = {
		regex = "^ *\\([0-9]\\+>\\)\\?\\(\\%([a-zA-Z]:\\)\\?[^ :(	\n][^:(	\n]*\\)(\\([0-9]\\+\\)) \\?: \\%(see declaration\\|\\%(warnin\\(g\\)\\|[a-z ]\\+\\) C[0-9]\\+:\\)",
		filename = 2,
		row = 3,
		type = { 4 },
	},
	edg_1 = {
		regex = "^\\([^ \n]\\+\\)(\\([0-9]\\+\\)): \\%(error\\|warnin\\(g\\)\\|remar\\(k\\)\\)",
		filename = 1,
		row = 2,
		type = { 3, 4 },
	},
	edg_2 = {
		regex = 'at line \\([0-9]\\+\\) of "\\([^ \n]\\+\\)"$',
		filename = 2,
		row = 1,
		type = M.level.INFO,
	},
	epc = {
		regex = "^Error [0-9]\\+ at (\\([0-9]\\+\\):\\([^)\n]\\+\\))",
		filename = 2,
		row = 1,
	},
	ftnchek = {
		regex = "\\(^Warning .*\\)\\? line[ \n]\\([0-9]\\+\\)[ \n]\\%(col \\([0-9]\\+\\)[ \n]\\)\\?file \\([^ :;\n]\\+\\)",
		filename = 4,
		row = 2,
		col = 3,
		type = { 1 },
	},
	gradle_kotlin = {
		regex = "^\\%(\\(w\\)\\|.\\): *\\(\\%([A-Za-z]:\\)\\?[^:\n]\\+\\): *(\\([0-9]\\+\\), *\\([0-9]\\+\\))",
		filename = 2,
		row = 3,
		col = 4,
		type = { 1 },
	},
	iar = {
		regex = '^"\\(.*\\)",\\([0-9]\\+\\)\\s-\\+\\%(Error\\|Warnin\\(g\\)\\)\\[[0-9]\\+\\]:',
		filename = 1,
		row = 2,
		type = { 3 },
	},
	ibm = {
		regex = "^\\([^( \n	]\\+\\)(\\([0-9]\\+\\):\\([0-9]\\+\\)) : \\%(warnin\\(g\\)\\|informationa\\(l\\)\\)\\?",
		filename = 1,
		row = 2,
		col = 3,
		type = { 4, 5 },
	},
	irix = {
		regex = '^[-[:alnum:]_/ ]\\+: \\%(\\%([sS]evere\\|[eE]rror\\|[wW]arnin\\(g\\)\\|[iI]nf\\(o\\)\\)[0-9 ]*: \\)\\?\\([^," \n	]\\+\\)\\%(, line\\|:\\) \\([0-9]\\+\\):',
		filename = 3,
		row = 4,
		type = { 1, 2 },
	},
	java = {
		regex = "^\\%([ 	]\\+at \\|==[0-9]\\+== \\+\\%(at\\|b\\(y\\)\\)\\).\\+(\\([^()\n]\\+\\):\\([0-9]\\+\\))$",
		filename = 2,
		row = 3,
		type = { 1 },
	},
	jikes_file = {
		regex = '^\\%(Found\\|Issued\\) .* compiling "\\(.\\+\\)":$',
		filename = 1,
		type = M.level.INFO,
	},
	maven = {
		regex = "^\\%(\\[\\%(ERROR\\|\\(WARNING\\)\\|\\(INFO\\)\\)] \\)\\?\\([^\n []\\%([^\n :]\\| [^\n/-]\\|:[^\n []\\)*\\):\\[\\([[:digit:]]\\+\\),\\([[:digit:]]\\+\\)] ",
		filename = 3,
		row = 4,
		col = 5,
		type = { 1, 2 },
	},
	clang_include = {
		regex = "^In file included from \\([^\n:]\\+\\):\\([0-9]\\+\\):$",
		filename = 1,
		row = 2,
		type = M.level.INFO,
	},
	gcc_include = {
		regex = "^\\%(In file included \\|                 \\|	\\)from \\([0-9]*[^0-9\n]\\%([^\n :]\\| [^-/\n]\\|:[^ \n]\\)\\{-}\\):\\([0-9]\\+\\)\\%(:\\([0-9]\\+\\)\\)\\?\\%(\\(:\\)\\|\\(,\\|$\\)\\)\\?",
		filename = 1,
		row = 2,
		col = 3,
		type = { 4, 5 },
	},
	["ruby_Test::Unit"] = {
		regex = "^    [[ ]\\?\\([^ (].*\\):\\([1-9][0-9]*\\)\\(\\]\\)\\?:in ",
		filename = 1,
		row = 2,
	},
	gmake = {
		regex = ": \\*\\*\\* \\[\\%(\\(.\\{-1,}\\):\\([0-9]\\+\\): .\\+\\)\\]",
		filename = 1,
		row = 2,
		type = M.level.INFO,
	},
	gnu = {
		regex = "^\\%([[:alpha:]][-[:alnum:].]\\+: \\?\\|[ 	]\\%(in \\| from\\)\\)\\?\\(\\%([0-9]*[^0-9\\n]\\)\\%([^\\n :]\\| [^-/\\n]\\|:[^ \\n]\\)\\{-}\\)\\%(: \\?\\)\\([0-9]\\+\\)\\%(-\\([0-9]\\+\\)\\%(\\.\\([0-9]\\+\\)\\)\\?\\|[.:]\\([0-9]\\+\\)\\%(-\\%(\\([0-9]\\+\\)\\.\\)\\([0-9]\\+\\)\\)\\?\\)\\?:\\%( *\\(\\%(FutureWarning\\|RuntimeWarning\\|W\\%(arning\\)\\|warning\\)\\)\\| *\\([Ii]nfo\\%(\\>\\|formationa\\?l\\?\\)\\|I:\\|\\[ skipping .\\+ ]\\|instantiated from\\|required from\\|[Nn]ote\\)\\| *\\%([Ee]rror\\)\\|\\%([0-9]\\?\\)\\%([^0-9\\n]\\|$\\)\\|[0-9][0-9][0-9]\\)",
		filename = 1,
		row = { 2, 3 },
		col = { 5, 4 },
		type = { 8, 9 },
	},
	lcc = {
		regex = "^\\%(E\\|\\(W\\)\\), \\([^(\n]\\+\\)(\\([0-9]\\+\\),[ 	]*\\([0-9]\\+\\)",
		filename = 2,
		row = 3,
		col = 4,
		type = { 1 },
	},
	makepp = {
		regex = "^makepp\\%(\\%(: warning\\(:\\).\\{-}\\|\\(: Scanning\\|: [LR]e\\?l\\?oading makefile\\|: Imported\\|log:.\\{-}\\) \\|: .\\{-}\\)`\\(\\(\\S \\{-1,}\\)\\%(:\\([0-9]\\+\\)\\)\\?\\)['(]\\)",
		filename = 4,
		row = 5,
		type = { 1, 2 },
	},
	mips_1 = {
		regex = " (\\([0-9]\\+\\)) in \\([^ \n]\\+\\)",
		filename = 2,
		row = 1,
	},
	mips_2 = {
		regex = " in \\([^()\n ]\\+\\)(\\([0-9]\\+\\))$",
		filename = 1,
		row = 2,
	},
	omake = {
		regex = "^\\*\\*\\* omake: file \\(.*\\) changed",
		filename = 1,
	},
	oracle = {
		regex = "^\\%(Semantic error\\|Error\\|PCC-[0-9]\\+:\\).* line \\([0-9]\\+\\)\\%(\\%(,\\| at\\)\\? column \\([0-9]\\+\\)\\)\\?\\%(,\\| in\\| of\\)\\? file \\(.\\{-}\\):\\?$",
		filename = 3,
		row = 1,
		col = 2,
	},
	perl = {
		regex = " at \\([^ \n]\\+\\) line \\([0-9]\\+\\)\\%([,.]\\|$\\| during global destruction\\.$\\)",
		filename = 1,
		row = 2,
	},
	php = {
		regex = "\\%(Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]\\+\\)",
		filename = 2,
		row = 3,
	},
	rxp = {
		regex = "^\\%(Error\\|Warnin\\(g\\)\\):.*\n.* line \\([0-9]\\+\\) char \\([0-9]\\+\\) of file://\\(.\\+\\)",
		filename = 4,
		row = 2,
		col = 3,
		type = { 1 },
	},
	sun = {
		regex = ": \\%(ERROR\\|WARNIN\\(G\\)\\|REMAR\\(K\\)\\) \\%([[:alnum:] ]\\+, \\)\\?File = \\(.\\+\\), Line = \\([0-9]\\+\\)\\%(, Column = \\([0-9]\\+\\)\\)\\?",
		filename = 3,
		row = 4,
		col = 5,
		type = { 1, 2 },
	},
	sun_ada = {
		regex = "^\\([^, \n	]\\+\\), line \\([0-9]\\+\\), char \\([0-9]\\+\\)[:., (-]",
		filename = 1,
		row = 2,
		col = 3,
	},
	watcom = {
		regex = "^[ 	]*\\(\\%([a-zA-Z]:\\)\\?[^ :(	\n][^:(	\n]*\\)(\\([0-9]\\+\\)): \\?\\%(\\(Error! E[0-9]\\+\\)\\|\\(Warning! W[0-9]\\+\\)\\):",
		filename = 1,
		row = 2,
		type = { 4 },
	},
	["4bsd"] = {
		regex = "\\%(^\\|::  \\|\\S ( \\)\\(/[^ \n	()]\\+\\)(\\([0-9]\\+\\))\\%(: \\(warning:\\)\\?\\|$\\| ),\\)",
		filename = 1,
		row = 2,
		type = { 3 },
	},
	["perl__Pod::Checker"] = {
		regex = "^\\*\\*\\* \\%(ERROR\\|\\(WARNING\\)\\).* \\%(at\\|on\\) line \\([0-9]\\+\\) \\%(.* \\)\\?in file \\([^ 	\n]\\+\\)",
		filename = 3,
		row = 2,
		type = { 1 },
	},
}

API

setup({opts})

Sets up the plugin for use.

Usage:

require("compile-mode").setup({
    -- you can disable colors by uncommenting this line
    -- no_baleia_support = true,
    default_command = "npm run build",
})

Valid keys and values for {opts}:

error_regexp_table

See Errors.

no_baleia_support

By default, compile-mode.nvim uses baleia.nvim to color in ANSI color escape sequences in the compilation buffer. You can disable this behavior by setting this config option to true.

default_command

The string to show in the compile() prompt as a default. You can set it to "" for an empty prompt. Defaults to: "make -k ".

time_format

The way to format the time displayed at the top of the compilation buffer. Passed into :h strftime(). Defaults to: "%a %b %e %H:%M:%S".

baleia_opts

Table of options to pass into baleia.setup(). Defaults to an empty table.

buffer_name

The name for the compilation buffer. Defaults to: "*compilation*".

error_highlights

A table of highlights to use for errors in the compilation buffer. The possible keys are:

  • {error} applied to the entire captured error (optional)
  • {error_row} applied to the number that specifies the row (or range of rows) of the error (optional)
  • {error_col} applied to the number that specifies the column (or range of columns) of the error (optional)
  • {error_filename} applied to the filename in which the error ocurred, when the error is of type ERROR (optional)
  • {warning_filename} applied to the filename in which the error ocurred, when the error is of type WARNING (optional)
  • {info_filename} applied to the filename in which the error ocurred, when the error is of type INFO (optional)

Each of the values is a table, with the following keys:

  • {background} (string) sets the :h guibg of the highlight group (optional)
  • {foreground} (string) sets the :h guifg of the highlight group (optional)
  • {gui} (string) sets the :h highlight-gui of the highlight group, and can be a comma-seperated list of attributes (optional)

You can use an empty table to remove all styles from a group.

`error_highlights` default

The defaults for error_highlights are:

default_highlights = {
	error = {
		gui = "underline",
	},
	error_row = {
		gui = "underline",
		foreground = theme[2],
	},
	error_col = {
		gui = "underline",
		foreground = theme[8],
	},
	error_filename = {
		gui = "bold,underline",
		foreground = theme[9],
	},
	warning_filename = {
		gui = "underline",
		foreground = theme[3],
	},
	info_filename = {
		gui = "underline",
		foreground = theme[14],
	},
}

debug

Print additional debug information. This is printed using print, so you can inspect it with :h :messages.

error_ignore_file_list

A list of Vim regexes to run each error's filename by, to check if this file should be ignored.

Defaults to: { "/bin/[a-z]*sh$" }. Passing in this option does not override this, but instead extends the list.

compilation_hidden_output

A Vim regex or list of Vim regexes run on every line in the compilation buffer which will be substituted with empty strings.

compile({param})

Run a command and place its output in the compilation buffer, reporting on its result. The command is run from the current working directory. The compilation buffer is opened in a new split if it isn't already opened. If {param.args} is not passed in, the user is prompted for a command using :h vim.ui.input().

Parameters

  • {param} (table) a table, identical to the tables passed into Neovim commands (optional)
    • {param.args}: the string of the command itself, or nil if the user should be prompted to enter a command
    • {param.smods}: a table - see the mods field of :h nvim_parse_cmd() for more
      • {param.smods.vertical}: makes the window split vertically if the compilation buffer is not yet open
      • {param.smods.silent}: does not print any information
      • {param.smods.split}: modifications for the placement of the split

recompile({param})

Reruns the last compiled command. See :Recompile.

Parameters

  • {param} (table) a table, identical to the tables passed into Neovim commands (optional)
    • {param.smods}: a table - see the mods field of :h nvim_parse_cmd() for more
      • {param.smods.vertical}: makes the window split vertically if the compilation buffer is not yet open
      • {param.smods.silent}: does not print any information
      • {param.smods.split}: modifications for the placement of the split

next_error()

Jumps to the next error within the compilation buffer. See :NextError.

prev_error()

Jumps to a prior error within the compilation buffer. See :PrevError.

goto_error()

Jumps to the error under the cursor. See :CompileGotoError.

interrupt()

Interrupts the currently running compilation. See :CompileInterrupt.

Commands

:Compile

Runs a command and places its output in the compilation buffer. The command is run from the current working directory. The compilation buffer is opened in a new split if it isn't already opened. If an argument is present, it is used as the command. Otherwise, the user is prompted using :h vim.ui.input().

You can run the command using :h :vert to split the window vertically. :h :aboveleft, :h :belowright, :h :topleft and :h :botright also modify the split. You can run the command using :h :silent to get rid of the "Compilation finished" messages. You can run the command with a :h count to set the size of the opened window, like :h :split.

:Recompile

Reruns the last compiled command. If there isn't one, the error is reported using :h vim.notify(). The compilation buffer is opened in a new split if it isn't already opened. The command is rerun from the directory in which it was originally run.

You can run the command using :h :vert to split the window vertically. :h :aboveleft, :h :belowright, :h :topleft and :h :botright also modify the split. You can run the command using :h :silent to get rid of the "Compilation finished" messages. You can run the command with a :h count to set the size of the opened window, like :h :split.

:NextError

Jump to the next error in the compilation buffer. This does not take the cursor into effect - it simply starts at the first error in the buffer and continues, one by one, from there. Once the last error in the buffer is reached the command has no effect and reports on this fact.

:PrevError

Jump to a prior error in the compilation buffer. This does not take the cursor into effect - it simply starts at the current error in the buffer and continues backwards, one by one, from there. As long as the current error is before the first error (the default until :NextError has not yet been used) this command has no effect and reports on this fact.

:CompileGotoError

Only available within the compilation buffer itself.

Jump to the error present in the line under the cursor. If no such error exists, the command reports on this fact.

Mapped to <CR> within the compilation buffer.

:CompileInterrupt

Only available within the compilation buffer itself.

Interrupt the currently running compilation command, reporting on this in the compilation buffer.

Mapped to <C-c> within the compilation buffer.

Contributing

Contributions are welcome in the form of GitHub issues and pull requests.

For contributing details see CONTRIBUTING.md.

compile-mode.nvim's People

Contributors

ej-shafran avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.