UNPKG

@shopify/theme-language-server-common

Version:

<h1 align="center" style="position: relative;" > <br> <img src="https://github.com/Shopify/theme-check-vscode/blob/main/images/shopify_glyph.png?raw=true" alt="logo" width="141" height="160"> <br> Theme Language Server </h1>

91 lines (81 loc) 3.13 kB
import { LiquidHtmlNode } from '@shopify/liquid-html-parser'; import { SourceCodeType } from '@shopify/theme-check-common'; import { PrepareRenameParams, PrepareRenameResult, RenameParams, TextDocumentPositionParams, WorkspaceEdit, } from 'vscode-languageserver-protocol'; import { DocumentManager } from '../documents'; import { findCurrentNode } from '@shopify/theme-check-common'; import { BaseRenameProvider } from './BaseRenameProvider'; import { HtmlTagNameRenameProvider } from './providers/HtmlTagNameRenameProvider'; import { LiquidVariableRenameProvider } from './providers/LiquidVariableRenameProvider'; import { Connection } from 'vscode-languageserver'; import { ClientCapabilities } from '../ClientCapabilities'; /** * RenameProvider is responsible for providing rename support for the theme language server. * * Rename is a pretty abstract concept, it can be renaming a tag name, a variable, a class name, etc. */ export class RenameProvider { private providers: BaseRenameProvider[]; constructor( connection: Connection, clientCapabilities: ClientCapabilities, private documentManager: DocumentManager, findThemeRootURI: (uri: string) => Promise<string>, ) { this.providers = [ new HtmlTagNameRenameProvider(documentManager), new LiquidVariableRenameProvider( connection, clientCapabilities, documentManager, findThemeRootURI, ), ]; } /** Prepare is for telling if you can rename this thing or not, and what text to rename */ async prepare(params: PrepareRenameParams): Promise<null | PrepareRenameResult> { const [currentNode, ancestors] = this.nodes(params); if (currentNode === null || ancestors === null) { return null; } const promises = this.providers.map((provider) => provider .prepare(currentNode as LiquidHtmlNode, ancestors as LiquidHtmlNode[], params) .catch(() => null), ); const results = await Promise.all(promises); return results.find(Boolean) ?? null; } /** Rename is for actually renaming something */ async rename(params: RenameParams): Promise<null | WorkspaceEdit> { const [currentNode, ancestors] = this.nodes(params); if (currentNode === null || ancestors === null) { return null; } const promises = this.providers.map((provider) => provider .rename(currentNode as LiquidHtmlNode, ancestors as LiquidHtmlNode[], params) .catch(() => null), ); const results = await Promise.all(promises); return results.find(Boolean) ?? null; } /** a helper for getting the node under the cursor and its ancestry */ private nodes( params: TextDocumentPositionParams, ): [LiquidHtmlNode, LiquidHtmlNode[]] | [null, null] { const document = this.documentManager.get(params.textDocument.uri); if (!document || document.type !== SourceCodeType.LiquidHtml) { return [null, null]; } if (!(document.ast instanceof Error)) { return findCurrentNode(document.ast, document.textDocument.offsetAt(params.position)); } return [null, null]; } }