UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

861 lines (860 loc) 29.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StaticItems = void 0; const vscode_languageserver_1 = require("vscode-languageserver"); const error_codes_1 = require("../../diagnostics/error-codes"); const markdown_builder_1 = require("../markdown-builder"); const types_1 = require("./types"); const snippets_1 = require("../snippets"); const EscapedChars = [ { label: '\\a', detail: 'alert character', documentation: 'escapes the alert character', }, { label: '\\b', detail: 'backspace character', documentation: 'escapes the backspace character', }, { label: '\\e', detail: 'escape character', documentation: 'escapes the escape character', }, { label: '\\f', detail: 'form feed character', documentation: 'escapes the form feed character', }, { label: '\\n', detail: 'newline character', documentation: 'escapes a newline character', }, { label: '\\r', detail: 'carriage return character', documentation: 'escapes the carriage return character', }, { label: '\\t', detail: 'tab character', documentation: 'escapes the tab character', }, { label: '\\v', detail: 'vertical tab character', documentation: 'escapes the vertical tab character', }, { label: '\\ ', detail: 'space character', documentation: 'escapes the space character', }, { label: '\\$', detail: 'dollar character', documentation: 'escapes the dollar character', }, { label: '\\\\', detail: 'backslash character', documentation: 'escapes the backslash character', }, { label: '\\*', detail: 'star character', documentation: 'escapes the star character', }, { label: '\\?', detail: 'question mark character', documentation: 'escapes the question mark character', }, { label: '\\~', detail: 'tilde character', documentation: 'escapes the tilde character', }, { label: '\\%', detail: 'percent character', documentation: 'escapes the percent character', }, { label: '\\#', detail: 'hash character', documentation: 'escapes the hash character', }, { label: '\\(', detail: 'left parenthesis character', documentation: 'escapes the left parenthesis character', }, { label: '\\)', detail: 'right parenthesis character', documentation: 'escapes the right parenthesis character', }, { label: '\\{', detail: 'left curly bracket character', documentation: 'escapes the left curly bracket character', }, { label: '\\}', detail: 'right curly bracket character', documentation: 'escapes the right curly bracket character', }, { label: '\\[', detail: 'left bracket character', documentation: 'escapes the left bracket character', }, { label: '\\]', detail: 'right bracket character', documentation: 'escapes the right bracket character', }, { label: '\\<', detail: 'less than character', documentation: 'escapes the less than character', }, { label: '\\>', detail: 'greater than character', documentation: 'escapes the more than character', }, { label: '\\^', detail: 'circumflex character', documentation: 'escapes the circumflex character', }, { label: '\\&', detail: 'ampersand character', documentation: 'escapes the ampersand character', }, { label: '\\;', detail: 'semicolon character', documentation: 'escapes the semicolon character', }, { label: '\\"', detail: 'quote character', documentation: 'escapes the quote character', }, { label: "\\'", detail: 'quote character', documentation: 'escapes the apostrophe character', }, { label: '\\xxx', detail: 'hexadecimal character', documentation: 'where xx is a hexadecimal number, escapes the ascii character with the specified value. For example, \\x9 is the tab character.', }, { label: '\\Xxx', detail: 'hexadecimal character', documentation: 'where xx is a hexadecimal number, escapes a byte of data with the specified value. If you are using a mutibyte encoding, this can be used to enter invalid strings. Only use this if you know what you are doing.', }, { label: '\\ooo', detail: 'octal character', documentation: 'where ooo is an octal number, escapes the ascii character with the specified value. For example, \\011 is the tab character.', }, { label: '\\uxxxx', detail: 'unicode character', documentation: 'where xxxx is a hexadecimal number, escapes the 16-bit Unicode character with the specified value. For example, \\u9 is the tab character.', }, { label: '\\Uxxxxxxxx', detail: 'unicode character', documentation: 'where xxxxxxxx is a hexadecimal number, escapes the 32-bit Unicode character with the specified value. For example, \\U9 is the tab character.', }, { label: '\\cx', detail: 'alphabet character', documentation: ' where x is a letter of the alphabet, escapes the control sequence generated by pressing the control key and the specified letter. for example, \\ci is the tab character', }, ]; const PrebuiltVars = [ ...snippets_1.PrebuiltDocumentationMap.getByType('variable').map((item) => { return { label: item.name, detail: 'variable', kind: vscode_languageserver_1.CompletionItemKind.Variable, documentation: item.description, useDocAsDetail: true, }; }), ]; const PrebuiltFuncs = [ ...snippets_1.PrebuiltDocumentationMap.getByType('command').map((item) => { return { label: item.name, detail: 'function', kind: vscode_languageserver_1.CompletionItemKind.Function, documentation: item.description, useDocAsDetail: true, }; }), ]; const Pipes = [ { label: '<', detail: 'READ <SOURCE_FILE', insertText: '<', documentation: 'To read standard input from a file, use <SOURCE_FILE', }, { label: '>', detail: 'WRITE >DESTINATION', insertText: '>', documentation: 'To write standard output to a file, use >DESTINATION', }, { label: '2>', detail: 'WRITE 2>DESTINATION', insertText: '2>', documentation: 'To write standard error to a file, use 2>DESTINATION', }, { label: '>>', detail: 'APPEND >>DESTINATION', insertText: '>>', documentation: 'To append standard output to a file, use >>DESTINATION', }, { label: '2>>', detail: 'APPEND 2>>DESTINATION', insertText: '2>>', documentation: 'To append standard error to a file, use 2>>DESTINATION', }, { label: '>?', detail: 'NOCLOBBER >? DESTINATION', insertText: '>?', documentation: 'To not overwrite (“clobber”) an existing file, use >?DESTINATION or 2>?DESTINATION. This is known as the “noclobber” redirection.', }, { label: '1>?', detail: 'NOCLOBBER 1>?DESTINATION', insertText: '1>?', documentation: 'To not overwrite (“clobber”) an existing file, use >?DESTINATION or 2>?DESTINATION. This is known as the “noclobber” redirection.', }, { label: '2>?', detail: 'NOCLOBBER 2>?DESTINATION', insertText: '2>?', documentation: 'To not overwrite (“clobber”) an existing file, use >?DESTINATION or 2>?DESTINATION. This is known as the “noclobber” redirection.', }, { label: '&-', detail: 'CLOSE &-', insertText: '&-', documentation: 'An ampersand followed by a minus sign (&-). The file descriptor will be closed.', }, { label: '|', detail: 'OUTPUT | INPUT', insertText: '|', documentation: 'Pipe one stream with another. Usually standard output of one command will be piped to standard input of another. OUTPUT | INPUT', }, { label: '&', detail: 'DISOWN &', insertText: '&', documentation: 'Disown output . OUTPUT &', }, { label: '&>', detail: 'STDOUT_AND_STDERR &>', insertText: '&>', documentation: 'the redirection &> can be used to direct both stdout and stderr to the same destination', }, { label: '&|', detail: 'STDOUT_AND_STDERR &|', insertText: '&|', documentation: 'the redirection &| can be used to direct both stdout and stderr to the same destination', }, ]; const StatusNumbers = [ { label: '0', detail: 'Status Success', documentation: 'Success exit status, generally means that the command executed successfully.', examples: [ types_1.CompletionExample.create('An implementation of the true command as a fish function:', 'function true', ' return 0', 'end'), types_1.CompletionExample.create('Using true in an if statement', 'if true', ' echo "This will be printed"', 'end', 'if !true', ' echo "This will not be printed"', 'end'), ], }, { label: '1', detail: 'Status Failure', documentation: 'Failure exit status, generally means that the command executed with an Error.', examples: [ types_1.CompletionExample.create('An implementation of the false command as a fish function:', 'function false', ' return 1', 'end'), types_1.CompletionExample.create('Using false in an if statement', 'if false', ' echo "This will not be printed"', 'end', 'if !false', ' echo "This will be printed"', 'end'), ], }, { label: '2', detail: 'Status Misuse', documentation: 'Misuse exit status, generally means that the command was used incorrectly.', examples: [ types_1.CompletionExample.create('as seen from the ls manpage:', 'ls /directory/nonexistent', 'echo $status # prints "2"'), ], }, { label: '121', detail: 'Status Invalid Arguments', documentation: 'is generally the exit status of commands if they were supplied with invalid arguments.', }, { label: '123', detail: 'Status Invalid Command', documentation: 'means that the command was not executed because the command name contained invalid characters.', }, { label: '124', detail: 'Status No Matches', documentation: 'means that the command was not executed because none of the wildcards in the command produced any matches.', }, { label: '125', detail: 'Status Invalid Privileges', documentation: 'means that while an executable with the specified name was located, the operating system could not actually execute the command.', }, { label: '126', detail: 'Status Not Executable', documentation: 'means that while a file with the specified name was located, it was not executable.', }, { label: '127', detail: 'Status Not Found', documentation: 'means that no function, builtin or command with the given name could be located.', }, ]; const StringRegex = [ { label: '*', detail: '0 >= MATCHES', documentation: 'refers to 0 or more repetitions of the previous expression', insertText: '*', insertTextFormat: 1, examples: [], }, { label: '^', detail: 'START of string', documentation: '^ is the start of the string or line, $ the end', insertText: '^', }, { label: '$', detail: 'END of string', documentation: '$ the end of string or line', insertText: '$', }, { label: '+', detail: '1 >= MATCHES', documentation: '1 or more', insertText: '+', insertTextFormat: 1, examples: [], }, { label: '?', detail: '0 or 1 MATCHES', documentation: '0 or 1.', insertText: '?', examples: [], }, { label: '{n}', detail: 'exactly n MATCHES', documentation: 'to exactly n (where n is a number)', insertText: '{n}', examples: [], }, { label: '{n,m}', detail: 'n <= MATCHES <= m', documentation: 'at least n, no more than m.', insertText: '{${1:n},${2:m}}', examples: [], }, { label: '{n,}', detail: 'n >= MATCHES', documentation: 'n or more', insertText: '{${1:number},}', insertTextFormat: 2, examples: [], }, { label: '.', detail: 'Alpha-numeric Character', documentation: "'.' any character except newline", insertText: '.', examples: [], }, { label: '\\d a decimal digit', detail: 'Decimal Character', documentation: '\\d a decimal digit and \\D, not a decimal digit', insertText: '\\d', examples: [], }, { label: '\\D not a decimal digit', detail: 'Not a Decimal Character', documentation: '\\d a decimal digit and \\D, not a decimal digit', insertText: '\\D', examples: [], }, { label: '\\s whitespace', detail: 'Whitespace Character', documentation: 'whitespace and \\S, not whitespace ', insertText: '\\s', examples: [], }, { label: '\\S not whitespace', detail: 'Not a Whitespace Character', documentation: '\\S, not whitespace and \\s whitespace', insertText: '\\S', examples: [], }, { label: '\\w a “word” character', detail: 'Word Character', documentation: '\\w a “word” character and \\W, a “non-word” character ', insertText: '\\w', }, { label: '\\W a “non-word” character', detail: 'Non-Word Character', documentation: 'a “non-word” character ', insertText: '\\W', }, { label: '[...] a character set', detail: 'Character Set', documentation: '[...] - (where “…” is some characters) is a character set ', insertText: '[...]', }, { label: '[^...]', detail: 'Inverse Character Set', documentation: '[^...] is the inverse of the given character set', insertText: '[^...]', }, { label: '[x-y] the range of characters from x-y', detail: 'Range of Characters', documentation: '[x-y] is the range of characters from x-y', insertText: '[x-y]', }, { label: '[[:xxx:]]', detail: 'Named Character Set', documentation: '[[:xxx:]] is a named character set', insertText: '[[:xxx:]]', }, { label: '[[:^xxx:]]', detail: 'Inverse Named Character Set', documentation: '[[:^xxx:]] is the inverse of a named character set', insertText: '[[:^xxx:]]', }, { label: '[[:alnum:]]', detail: 'Alphanumeric Character', documentation: '[[:alnum:]] : “alphanumeric”', insertText: '[[:alnum:]]', }, { label: '[[:alpha:]]', detail: 'Alphabetic Character', documentation: '[[:alpha:]] : “alphabetic”', insertText: '[[:alpha:]]', }, { label: '[[:ascii:]]', detail: 'ASCII Character', documentation: '[[:ascii:]] : “0-127', insertText: '[[:ascii:]]', }, { label: '[[:blank:]]', detail: 'Space or Tab', documentation: '[[:blank:]] : “space or tab”', insertText: '[[:blank:]]', }, { label: '[[:cntrl:]]', detail: 'Control Character', documentation: '[[:cntrl:]] : “control character”', insertText: '[[:cntrl:]]', }, { label: '[[:digit:]]', detail: 'Decimal Digit', documentation: '[[:digit:]] : “decimal digit”', insertText: '[[:digit:]]', }, { label: '[[:graph:]]', detail: 'Printing Character', documentation: '[[:graph:]] : “printing, excluding space”', insertText: '[[:graph:]]', }, { label: '[[:lower:]]', detail: 'Lower Case Letter', documentation: '[[:lower:]] : “lower case letter”', insertText: '[[:lower:]]', }, { label: '[[:print:]]', detail: 'Printing Character', documentation: '[[:print:]] : “printing, including space”', insertText: '[[:print:]]', }, { label: '[[:punct:]]', detail: 'Punctuation Character', documentation: '[[:punct:]] : “printing, excluding alphanumeric”', insertText: '[[:punct:]]', }, { label: '[[:space:]]', detail: 'White Space Character', documentation: '[[:space:]] : “white space”', insertText: '[[:space:]]', }, { label: '[[:upper:]]', detail: 'Upper Case Letter', documentation: '[[:upper:]] : “upper case letter”', insertText: '[[:upper:]]', }, { label: '[[:word:]]', detail: 'Word Character', documentation: '[[:word:]] : “same as w”', insertText: '[[:word:]]', }, { label: '[[:xdigit:]]', detail: 'Hexadecimal Digit', documentation: '[[:xdigit:]] : “hexadecimal digit”', insertText: '[[:xdigit:]]', }, { label: '(...)', detail: 'Capturing Group', documentation: '(...) is a capturing group', insertText: '(...)', }, { label: '(?:...) is a non-capturing group', detail: 'Non-Capturing Group', documentation: '(?:...) is a non-capturing group', insertText: '(?:...)', }, { label: '\\n', detail: 'Backreference', documentation: '\\n is a backreference (where n is the number of the group, starting with 1)', insertText: '\\', }, { label: '$n', detail: 'Reference', documentation: '$n is a reference from the replacement expression to a group in the match expression.', insertText: '$', }, { label: '\\b', detail: 'Word Boundary', documentation: '\\b denotes a word boundary, \\B is not a word boundary.', insertText: '\\b', }, { label: '|', detail: 'Alternation', documentation: '| is “alternation”, i.e. the “or”.', insertText: '|', }, ]; const FormatStrings = [ { label: '%d', detail: 'Decimal Integer', documentation: 'Argument will be used as decimal integer (signed or unsigned)', }, { label: '%i', detail: 'Decimal Integer', documentation: 'Argument will be used as decimal integer (signed or unsigned)', }, { label: '%o', detail: 'Octal Integer', documentation: 'An octal unsigned integer', }, { label: '%u', detail: 'Unsigned Integer', documentation: 'An unsigned decimal integer - this means negative numbers will wrap around', }, { label: '%x', detail: 'Hexadecimal Integer', documentation: 'An unsigned hexadecimal integer', }, { label: '%X', detail: 'Hexadecimal Integer', documentation: 'An unsigned hexadecimal integer', }, { label: '%f', detail: 'Floating Point', documentation: 'A floating-point number. %f defaults to 6 places after the decimal point (which is locale-dependent - e.g. in de_DE it will be a ,).', }, { label: '%g', detail: 'Floating Point', documentation: 'will trim trailing zeroes and switch to scientific notation (like %e) if the numbers get small or large enough.', }, { label: '%G', detail: 'Floating Point', documentation: 'will trim trailing zeroes and switch to scientific notation (like %e) if the numbers get small or large enough.', }, { label: '%s', detail: 'String', documentation: 'A string', }, { label: '%b', detail: 'Word Boundary', documentation: 'As a string, interpreting backslash escapes, except that octal escapes are of the form 0 or 0ooo.', }, { label: '%%', detail: 'Literal Percent', documentation: 'Signifies a literal "%"', }, ]; const Combiners = [ { label: 'and', detail: 'and CONDITION; COMMANDS; end', documentation: 'is a combiner that combines two commands with a logical and. The second command is only executed if the first command returns true.', }, { label: 'or', detail: 'or CONDITION; COMMANDS; end', documentation: 'is a combiner that combines two commands with a logical or. The second command is only executed if the first command returns false.', }, { label: 'not', detail: 'not CONDITION; COMMANDS; end', documentation: 'not negates the exit status of another command. If the exit status is zero, not returns 1. Otherwise, not returns 0.', }, { label: '||', detail: '|| CONDITION; COMMANDS; end', documentation: 'is a combiner that combines two commands with a logical or. The second command is only executed if the first command returns false.', }, { label: '&&', detail: '&& CONDITION; COMMANDS; end', documentation: 'is a combiner that combines two commands with a logical and. The second command is only executed if the first command returns true.', }, { label: '!', detail: '! CONDITION; COMMANDS; end', documentation: 'not negates the exit status of another command. If the exit status is zero, not returns 1. Otherwise, not returns 0.', }, ]; const Statements = [ { label: 'if', detail: 'if CONDITION; COMMANDS; end', documentation: 'if is a conditional statement that executes a command if a condition is true.', }, { label: 'else if', detail: 'else if CONDITION; COMMANDS; end', documentation: 'else if is a conditional statement that executes a command if a condition is true.', }, { label: 'else', detail: 'else; COMMANDS; end', documentation: 'else is a conditional statement that executes a command if a condition is true.', }, { label: 'switch', detail: 'switch CONDITION; case VALUE; COMMANDS; end; end', documentation: 'switch is a conditional statement that executes a command if a condition is true.', }, { label: 'while', detail: 'while CONDITION; COMMANDS; end', documentation: 'while is a conditional statement that executes a command if a condition is true. (Works like a repeated "if" statement)', }, ]; const shebangs = [ { label: '#!/usr/bin/env fish', fishKind: 'shebang', detail: 'execute script using fish env', documentation: 'execute script using fish env', }, { label: '#!/usr/local/bin/fish', fishKind: 'shebang', detail: '#!/usr/local/bin/fish', documentation: 'Check this path exists. Could be /usr/bin/fish, /usr/local/bin/fish, or /bin/fish', }, { label: '#!/usr/bin/fish', fishKind: 'shebang', detail: '#!/usr/bin/fish', documentation: 'Check this path exists. Could be /usr/bin/fish, /usr/local/bin/fish, or /bin/fish', }, { label: '#!/bin/fish', fishKind: 'shebang', detail: '#!/bin/fish', documentation: 'Check this path exists. Could be /usr/bin/fish, /usr/local/bin/fish, or /bin/fish', }, ]; const disableDiagnostics = Object.values(error_codes_1.ErrorCodes.codes).map((diagnostic) => { return { label: `${diagnostic.code}`, detail: diagnostic.message, useDocAsDetail: true, documentation: [ `# Error code: ${diagnostic.code}`, markdown_builder_1.md.separator(), `${diagnostic.message}`, markdown_builder_1.md.separator(), `DIAGNOSTIC LEVEL: ${error_codes_1.ErrorCodes.getSeverityString(diagnostic.severity)}`, ].join('\n'), insertText: `${diagnostic.code}`, }; }); const comments = [ { label: '# @fish-lsp-disable', detail: 'Disable all LSP diagnostics for this file', fishKind: types_1.FishCompletionItemKind.COMMENT, documentation: [ '# Disable all LSP diagnostics for this file', markdown_builder_1.md.separator(), 'This directive will disable all diagnostics for this file. This is useful when you want to ignore all diagnostics for a file.', '___', '```fish', '# @fish-lsp-disable', 'alias ls "ls -l" # no more warnings', '```', '```fish', '# @fish-lsp-disable 2002', 'alias ls="ls -l" # no more warnings', '# @fish-lsp-enable', 'alias ls="ls -l" # warnings enabled again', '```', ].join('\n'), }, { label: '# @fish-lsp-enable', detail: 'Enable all LSP diagnostics for this file', kind: vscode_languageserver_1.CompletionItemKind.Enum, fishKind: types_1.FishCompletionItemKind.COMMENT, documentation: [ '# Enables all LSP diagnostics for this file', markdown_builder_1.md.separator(), 'This directive will enable all diagnostics for this file. This is useful when you want to turn diagnostics on & off in sections.', '___', '```fish', '# @fish-lsp-disable', 'alias ls "ls -l" # no more warnings', '```', '```fish', '# @fish-lsp-disable 2002', 'alias ls="ls -l" # no more warnings', '# @fish-lsp-enable', 'alias ls="ls -l" # warnings enabled again', '```', ].join('\n'), }, { label: '# @fish-lsp-disable-next-line', detail: 'Disables all LSP diagnostics for the next line', fishKind: types_1.FishCompletionItemKind.COMMENT, documentation: [ '# Disables LSP diagnostics for the next line.', markdown_builder_1.md.separator(), ' Any enabled diagnostics inside the file, before this comment will be enabled again after this line.', '___', '```fish', '# @fish-lsp-disable-next-line', 'alias ls "ls -a" # no more warnings', '```', '```fish', '# @fish-lsp-disable-next-line 2002', 'alias ls="ls -1" # no more warnings', 'alias lsl="ls -l" # warnings enabled again', '```', ].join('\n'), }, { label: '# @fish-lsp-enable-next-line', detail: 'Enable LSP diagnostics for next line', fishKind: types_1.FishCompletionItemKind.COMMENT, documentation: [ '# Enables LSP diagnostics for next line', markdown_builder_1.md.separator(), 'This directive will enable all diagnostics for the next line.', '___', '```fish', '# @fish-lsp-disable', 'alias ls "ls -a" # warnings are disabled in this file', '# @fish-lsp-enable-next-line', 'alias lsl="ls -l" # warnings temporarily enabled again', 'alias lss "ls -s" # no more warnings again', '```', ].join('\n'), }, ]; exports.StaticItems = { [types_1.FishCompletionItemKind.ESC_CHARS]: EscapedChars, [types_1.FishCompletionItemKind.PIPE]: Pipes, [types_1.FishCompletionItemKind.STATUS]: StatusNumbers, [types_1.FishCompletionItemKind.REGEX]: StringRegex, [types_1.FishCompletionItemKind.FORMAT_STR]: FormatStrings, [types_1.FishCompletionItemKind.COMBINER]: Combiners, [types_1.FishCompletionItemKind.STATEMENT]: Statements, [types_1.FishCompletionItemKind.SHEBANG]: shebangs, [types_1.FishCompletionItemKind.COMMENT]: comments, [types_1.FishCompletionItemKind.DIAGNOSTIC]: disableDiagnostics, [types_1.FishCompletionItemKind.VARIABLE]: PrebuiltVars, [types_1.FishCompletionItemKind.FUNCTION]: PrebuiltFuncs, };