UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

118 lines (102 loc) 3.39 kB
import { Command, Position, Range, TextEdit } from 'vscode-languageserver'; import { FishCommandCompletionItem, FishCompletionData } from './types'; import { StaticItems } from './static-items'; import { SyntaxNode } from 'web-tree-sitter'; import { DIAGNOSTIC_COMMENT_REGEX, DiagnosticAction, isValidErrorCode } from '../../diagnostics/comments-handler'; import { FishCompletionList } from './list'; import { SetupData } from './pager'; import { ErrorCodes } from '../../diagnostics/errorCodes'; export function buildCommentCompletions( line: string, position: Position, node: SyntaxNode, data: SetupData, word: string, ) { // FishCompletionItem.createData(data.uri, line, ,detail, documentation) const hashIndex = line.indexOf('#'); // Create range from the # character to cursor const range = Range.create( Position.create(position.line, hashIndex), position, ); // Command to retrigger completion const retriggerCommand: Command = { title: 'Suggest', command: 'editor.action.triggerSuggest', }; const completions: FishCommandCompletionItem[] = []; if (position.line === 0) { completions.push( ...StaticItems.shebang.map(item => { item.textEdit = TextEdit.replace(range, item.label); return item; }), ); } /** * add diagnostic comment strings: * `# @fish-lsp-disable` */ const diagnosticComment = getCommentDiagnostics(line, position.line); if (!diagnosticComment) { completions.push( ...StaticItems.comment.map((item) => { item.textEdit = TextEdit.replace(range, `${item.label} `); item.command = retriggerCommand; return item; })); } /** * add diagnostic codes to the completion list * `# @fish-lsp-disable 1001` */ if (diagnosticComment) { if (diagnosticComment?.codes) { const codeStrings = diagnosticComment?.codes.map(code => code.toString()); completions.push( ...StaticItems.diagnostic .filter(item => !codeStrings.includes(item.label)) .map((item) => { item.command = retriggerCommand; item.insertText = `${item.label} `; return item; }), ); } } const completionData: FishCompletionData = { word, position, uri: data.uri, line, }; return FishCompletionList.create(false, completionData, completions); } function getCommentDiagnostics(line: string, lineNumber: number) { const match = line.trim().match(DIAGNOSTIC_COMMENT_REGEX); if (!match) return null; const [, action, nextLine, codesStr] = match; const codeStrings = codesStr ? codesStr.trim().split(/\s+/) : []; // Parse the diagnostic codes if present const parsedCodes = codeStrings .map(codeStr => parseInt(codeStr, 10)) .filter(code => !isNaN(code)); const validCodes: ErrorCodes.codeTypes[] = []; const invalidCodes: string[] = []; codeStrings.forEach((codeStr, idx) => { const code = parsedCodes[idx]; if (code && !isNaN(code) && isValidErrorCode(code)) { validCodes.push(code as ErrorCodes.codeTypes); } else { invalidCodes.push(codeStr); } }); return { action: action as DiagnosticAction, target: nextLine ? 'next-line' : 'line', codes: validCodes, lineNumber: lineNumber, invalidCodes: invalidCodes.length > 0 ? invalidCodes : undefined, }; }