fish-lsp
Version:
LSP implementation for fish/fish-shell
142 lines (124 loc) • 5.03 kB
text/typescript
// 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));
}