UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

142 lines (124 loc) 5.03 kB
// https://github.com/typescript-language-server/typescript-language-server/blob/5a39c1f801ab0cad725a2b8711c0e0d46606a08b/src/utils/typeConverters.ts#L12 import * as LSP from 'vscode-languageserver'; import { FishProtocol } from './fishProtocol'; import * as TS from 'web-tree-sitter'; export namespace Range { export const create = (start: LSP.Position, end: LSP.Position): LSP.Range => LSP.Range.create(start, end); export const is = (value: any): value is LSP.Range => LSP.Range.is(value); export const fromTextSpan = (span: FishProtocol.TextSpan): LSP.Range => fromLocations(span.start, span.end); export const toTextSpan = (range: LSP.Range): FishProtocol.TextSpan => ({ start: Position.toLocation(range.start), end: Position.toLocation(range.end), }); export const fromLocations = (start: FishProtocol.Location, end: FishProtocol.Location): LSP.Range => LSP.Range.create( Math.max(0, start.line - 1), Math.max(start.offset - 1, 0), Math.max(0, end.line - 1), Math.max(0, end.offset - 1)); export const toFileRangeRequestArgs = (file: string, range: LSP.Range): FishProtocol.FileRangeRequestArgs => ({ file, startLine: range.start.line + 1, startOffset: range.start.character + 1, endLine: range.end.line + 1, endOffset: range.end.character + 1, }); export const toFormattingRequestArgs = (file: string, range: LSP.Range): FishProtocol.FormatRequestArgs => ({ file, line: range.start.line + 1, offset: range.start.character + 1, endLine: range.end.line + 1, endOffset: range.end.character + 1, }); export function intersection(one: LSP.Range, other: LSP.Range): LSP.Range | undefined { const start = Position.Max(other.start, one.start); const end = Position.Min(other.end, one.end); if (Position.isAfter(start, end)) { // this happens when there is no overlap: // |-----| // |----| return undefined; } return LSP.Range.create(start, end); } } export namespace Position { export const create = (line: number, character: number): LSP.Position => LSP.Position.create(line, character); export const is = (value: any): value is LSP.Position => LSP.Position.is(value); export const fromLocation = (fishlocation: FishProtocol.Location): LSP.Position => { // Clamping on the low side to 0 since Typescript returns 0, 0 when creating new file // even though position is supposed to be 1-based. return { line: Math.max(fishlocation.line - 1, 0), character: Math.max(fishlocation.offset - 1, 0), }; }; export const toLocation = (position: LSP.Position): FishProtocol.Location => ({ line: position.line + 1, offset: position.character + 1, }); export const toFileLocationRequestArgs = (file: string, position: LSP.Position): FishProtocol.FileLocationRequestArgs => ({ file, line: position.line + 1, offset: position.character + 1, }); export function Min(): undefined; export function Min(...positions: LSP.Position[]): LSP.Position; export function Min(...positions: LSP.Position[]): LSP.Position | undefined { if (!positions.length) { return undefined; } let result = positions.pop()!; for (const p of positions) { if (isBefore(p, result)) { result = p; } } return result; } export function isBefore(one: LSP.Position, other: LSP.Position): boolean { if (one.line < other.line) { return true; } if (other.line < one.line) { return false; } return one.character < other.character; } export function Max(): undefined; export function Max(...positions: LSP.Position[]): LSP.Position; export function Max(...positions: LSP.Position[]): LSP.Position | undefined { if (!positions.length) { return undefined; } let result = positions.pop()!; for (const p of positions) { if (isAfter(p, result)) { result = p; } } return result; } export function isAfter(one: LSP.Position, other: LSP.Position): boolean { return !isBeforeOrEqual(one, other); } export function isBeforeOrEqual(one: LSP.Position, other: LSP.Position): boolean { if (one.line < other.line) { return true; } if (other.line < one.line) { return false; } return one.character <= other.character; } export function fromSyntaxNode(node: TS.SyntaxNode): {start: LSP.Position; end: LSP.Position;} { return { start: create(node.startPosition.row, node.endPosition.column), end: create(node.endPosition.row, node.endPosition.column), }; } } export namespace Location { export const create = (uri: string, range: LSP.Range): LSP.Location => LSP.Location.create(uri, range); export const is = (value: any): value is LSP.Location => LSP.Location.is(value); export const fromTextSpan = (resource: LSP.DocumentUri, fishTextSpan: FishProtocol.TextSpan): LSP.Location => LSP.Location.create(resource, Range.fromTextSpan(fishTextSpan)); }