vscode#Hover TypeScript Examples

The following examples show how to use vscode#Hover. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ahkHoverProvider.ts    From vscode-autohotkey with MIT License 6 votes vote down vote up
public async provideHover(document: TextDocument, position: Position, token: CancellationToken) {

        const context = this.buildContext(document, position)

        const snippetHover = this.tryGetSnippetHover(context)
        if (snippetHover) {
            return snippetHover;
        }

        const method = await Parser.getMethodByName(document, context.word)
        if (method) {
            const markdonw = new MarkdownString("", true).appendCodeblock(method.full)
            if (method.comment) {
                markdonw.appendText(method.comment)
            }
            return new Hover(markdonw)
        }

        return null
    }
Example #2
Source File: hoverProvider.ts    From vscode-stripe with MIT License 6 votes vote down vote up
async provideHover(
    document: TextDocument,
    position: Position,
    token: CancellationToken,
  ): Promise<Hover | undefined> {
    const languageClient: LanguageClient | undefined = await getActiveJavaLanguageClient();

    if (!languageClient) {
      return undefined;
    }

    if (javaServerMode === ServerMode.STANDARD) {
      if (!this.delegateProvider) {
        this.delegateProvider = createClientHoverProvider(languageClient);
      }
      return this.delegateProvider.provideHover(document, position, token);
    } else {
      const params = {
        textDocument: languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document),
        position: languageClient.code2ProtocolConverter.asPosition(position),
      };
      const hoverResponse = await languageClient.sendRequest(HoverRequest.type, params, token);
      return languageClient.protocol2CodeConverter.asHover(hoverResponse);
    }
  }
Example #3
Source File: AbbreviationHoverProvider.ts    From vscode-lean4 with Apache License 2.0 6 votes vote down vote up
provideHover(document: TextDocument, pos: Position): Hover | undefined {
		const context = document.lineAt(pos.line).text.substr(pos.character);
		const symbolsAtCursor = this.abbreviations.findSymbolsIn(context);
		const allAbbrevs = symbolsAtCursor.map((symbol) => ({
			symbol,
			abbrevs: this.abbreviations.getAllAbbreviations(symbol),
		}));

		if (
			allAbbrevs.length === 0 ||
			allAbbrevs.every((a) => a.abbrevs.length === 0)
		) {
			return undefined;
		}

		const leader = this.config.abbreviationCharacter.get();

		const hoverMarkdown = allAbbrevs
			.map(
				({ symbol, abbrevs }) =>
					`Type ${symbol} using ${abbrevs
						.map((a) => '`' + leader + a + '`')
						.join(' or ')}`
			)
			.join('\n\n');

		const maxSymbolLength = Math.max(
			...allAbbrevs.map((a) => a.symbol.length)
		);
		const hoverRange = new Range(pos, pos.translate(0, maxSymbolLength));

		return new Hover(hoverMarkdown, hoverRange);
	}
Example #4
Source File: gopExtraInfo.ts    From vscode-goplus with Apache License 2.0 6 votes vote down vote up
public provideHover(document: TextDocument, position: Position, token: CancellationToken): Thenable<Hover> {
		if (!this.goPlusConfig) {
			this.goPlusConfig = getGoPlusConfig(document.uri);
		}
		let goPlusConfig = this.goPlusConfig;

		// Temporary fix to fall back to godoc if guru is the set docsTool
		if (goPlusConfig['docsTool'] === 'guru') {
			goPlusConfig = Object.assign({}, goPlusConfig, { docsTool: 'godoc' });
		}
		return definitionLocation(document, position, goPlusConfig, true, token).then(
			(definitionInfo) => {
				if (definitionInfo == null) {
					return null;
				}
				const lines = definitionInfo.declarationlines
					.filter((line) => line !== '')
					.map((line) => line.replace(/\t/g, '    '));
				let text;
				text = lines.join('\n').replace(/\n+$/, '');
				const hoverTexts = new vscode.MarkdownString();
				hoverTexts.appendCodeblock(text, 'go');
				if (definitionInfo.doc != null) {
					hoverTexts.appendMarkdown(definitionInfo.doc);
				}
				const hover = new Hover(hoverTexts);
				return hover;
			},
			() => {
				return null;
			}
		);
	}
Example #5
Source File: lexMode.ts    From yash with MIT License 6 votes vote down vote up
export function getLEXMode(lexLanguageService: LEXLanguageService): LanguageMode {
    const cache = CreateDocumentCache<LexDocument>(10, 60, document => lexLanguageService.parseLexDocument(document));
    return {
        getId() {
            return 'lex';
        },
        doValidation(document: TextDocument): Diagnostic[] {
            const lex = cache.get(document);
            return lexLanguageService.doValidation(document, lex);
        },
        doComplete(document: TextDocument, position: Position): CompletionList | CompletionItem[] {
            const lex = cache.get(document);
            return lexLanguageService.doComplete(document, position, lex);
        },
        doHover(document: TextDocument, position: Position): Hover | null {
            const lex = cache.get(document);
            return lexLanguageService.doHover(document, position, lex);
        },
        findDefinition(document: TextDocument, position: Position): Definition | null {
            const lex = cache.get(document);
            return lexLanguageService.findDefinition(document, position, lex);
        },
        findReferences(document: TextDocument, position: Position): Location[] {
            const lex = cache.get(document);
            return lexLanguageService.findReferences(document, position, lex);
        },
        doRename(document: TextDocument, position: Position, newName: string): WorkspaceEdit | null {
            const lex = cache.get(document);
            return lexLanguageService.doRename(document, position, newName, lex);
        },
        onDocumentRemoved(document: TextDocument) {
            cache.onDocumentRemoved(document);
        },
        dispose() {
            cache.dispose();
        }
    };
}
Example #6
Source File: lexHover.ts    From yash with MIT License 6 votes vote down vote up
export function doLEXHover(document: TextDocument, position: Position, lexDocument: LexDocument): Hover | null {
    const offset = document.offsetAt(position);
    const node = lexDocument.getEmbeddedCode(offset);
    if (node) {
        return null;
    }

    const word = document.getText(document.getWordRangeAtPosition(position));
    var symbol: ISymbol = lexDocument.defines[word] || lexDocument.states[word];
    if (symbol) {
        const line = document.lineAt(document.positionAt(symbol.offset)).text;
        return { contents: [createMarkedCodeString(line, 'lex')] };
    } else if (predefinedStates[word]) {
        return { contents: [createMarkedCodeString(predefinedStates[word], 'lex')] };
    }

    return null;
}
Example #7
Source File: spHoverProvider.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
export function hoverProvider(
  itemsRepo: ItemsRepository,
  document: TextDocument,
  position: Position,
  token: CancellationToken
): Hover | undefined {
  const items = itemsRepo.getItemFromPosition(document, position);
  orderItems(items);
  if (items.length > 0 && items[0].toHover()) {
    return items[0].toHover() as Hover;
  }
  return undefined;
}
Example #8
Source File: spTypesetItem.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
toHover(): Hover | undefined {
    if (!this.description) {
      return undefined;
    }
    return new Hover([
      { language: "sourcepawn", value: `typedef ${this.name}` },
      descriptionToMD(this.description),
    ]);
  }
Example #9
Source File: spTypedefItem.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
toHover(): Hover | undefined {
    if (!this.description) {
      return undefined;
    }
    return new Hover([
      { language: "sourcepawn", value: this.details },
      descriptionToMD(this.description),
    ]);
  }
Example #10
Source File: spPropertyItem.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
toHover(): Hover | undefined {
    if (!this.description) {
      return undefined;
    }
    return new Hover([
      { language: "sourcepawn", value: this.name },
      descriptionToMD(this.description),
    ]);
  }
Example #11
Source File: spMethodmapItem.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
toHover(): Hover {
    if (!this.description) {
      return new Hover([{ language: "sourcepawn", value: this.detail }]);
    }
    let filename: string = basename(this.filePath, ".inc");
    if (this.IsBuiltIn) {
      return new Hover([
        { language: "sourcepawn", value: this.detail },
        `[Online Documentation](https://sourcemod.dev/#/${filename}/methodmap.${this.name})`,
        descriptionToMD(this.description),
      ]);
    }
    return new Hover([
      { language: "sourcepawn", value: this.detail },
      descriptionToMD(this.description),
    ]);
  }
Example #12
Source File: spMethodItem.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
toHover(): Hover {
    if (!this.description) {
      return new Hover([{ language: "sourcepawn", value: this.detail }]);
    }
    let filename: string = basename(this.filePath, ".inc");
    if (this.IsBuiltIn) {
      return new Hover([
        { language: "sourcepawn", value: this.detail },
        `[Online Documentation](https://sourcemod.dev/#/${filename}/methodmap.${this.parent}/function.${this.name})`,
        descriptionToMD(
          `${this.description}${
            this.deprecated ? `\nDEPRECATED ${this.deprecated}` : ""
          }`
        ),
      ]);
    }
    return new Hover([
      { language: "sourcepawn", value: this.detail },
      descriptionToMD(
        `${this.description}${
          this.deprecated ? `\nDEPRECATED ${this.deprecated}` : ""
        }`
      ),
    ]);
  }
Example #13
Source File: spFunctionItem.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
toHover(): Hover {
    let filename: string = basename(this.filePath, ".inc");
    if (this.description == "") {
      return new Hover({ language: "sourcepawn", value: this.detail });
    }
    if (this.IsBuiltIn) {
      return new Hover([
        { language: "sourcepawn", value: this.detail },
        `[Online Documentation](https://sourcemod.dev/#/${filename}/function.${this.name})`,
        descriptionToMD(
          `${this.description}${
            this.deprecated ? `\nDEPRECATED ${this.deprecated}` : ""
          }`
        ),
      ]);
    }
    return new Hover([
      { language: "sourcepawn", value: this.detail },
      descriptionToMD(
        `${this.description}${
          this.deprecated ? `\nDEPRECATED ${this.deprecated}` : ""
        }`
      ),
    ]);
  }
Example #14
Source File: spEnumStructItem.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
toHover(): Hover | undefined {
    if (!this.description) {
      return undefined;
    }
    return new Hover([
      { language: "sourcepawn", value: this.name },
      descriptionToMD(this.description),
    ]);
  }
Example #15
Source File: spEnumItem.ts    From sourcepawn-vscode with MIT License 6 votes vote down vote up
toHover(): Hover | undefined {
    if (!this.description) {
      return undefined;
    }
    return new Hover([
      { language: "sourcepawn", value: this.name },
      descriptionToMD(this.description),
    ]);
  }
Example #16
Source File: ahkHoverProvider.ts    From vscode-autohotkey with MIT License 6 votes vote down vote up
private tryGetSnippetHover(context: Context): Hover {
        let snippetKey = context.word.toLowerCase();
        if (context.nextChart == "(") {
            snippetKey += "()"
        }
        const snippet = this.snippetCache.get(snippetKey)
        if (snippet) {
            const content = new MarkdownString(null, true)
                .appendCodeblock(snippet.body, 'ahk')
            if (snippet.description) {
                 content.appendText(snippet.description)
            }
            return new Hover(content)
        }
    }
Example #17
Source File: element-hover-provider.ts    From element-ui-helper with MIT License 6 votes vote down vote up
provideHover(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<Hover> {
    this._document = document
    this._position = position
    this._token = token

    const tag: TagObject | undefined = this.getTag()

    if (!/^[E|e]l/.test(tag?.text || '')) {
      // 如果不是element的标签(E|el开头) 则返回 null 表示没有hover
      return null
    }

    const attr = this.getAttr()
    const range = this.getHoverRange(attr)

    return this.getHoverInstance(tag, attr, range)
  }
Example #18
Source File: element-hover-provider.ts    From element-ui-helper with MIT License 6 votes vote down vote up
/**
   * 创建Hover实例
   *
   * @param language 语言
   * @param tag 标签
   * @param attr 属性
   * @param range 范围
   */
  createHoverInstance(language: ExtensionLanguage, tag: string, attr: string, range: Range): null | Hover {
    let document: Record<string, any> = localDocument[language]
    if (tag === attr) {
      attr = ''
    }
    if (Object.prototype.hasOwnProperty.call(document, tag)) {
      const tagDocument = document[tag]
      const hoverMarkdownStrings: MarkdownString[] = []
      Object.keys(tagDocument).forEach((key: string) => {
        const hoverMarkdownString: MarkdownString = HoverDocumentGenerator.getInstance().generate<ElDocument>(tagDocument, key, tag, attr, language)
        if (hoverMarkdownString) {
          hoverMarkdownStrings.push(hoverMarkdownString)
        }
      })
      return new Hover(hoverMarkdownStrings, range)
    } else {
      return null
    }
  }
Example #19
Source File: spIncludeItem.ts    From sourcepawn-vscode with MIT License 5 votes vote down vote up
toHover(): Hover {
    return new Hover(URI.parse(this.filePath).fsPath);
  }
Example #20
Source File: hoverProvider.ts    From vscode-stripe with MIT License 5 votes vote down vote up
async provideHover(
    document: TextDocument,
    position: Position,
    token: CancellationToken,
  ): Promise<Hover | undefined> {
    let contents: any[] = [];
    let range;

    const params = {
      textDocument: this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document),
      position: this.languageClient.code2ProtocolConverter.asPosition(position),
    };

    // get javs doc convent from server
    const hoverResponse = await this.languageClient.sendRequest(HoverRequest.type, params, token);

    // parse for stripe api hover content
    let stripeApiHoverContent;
    if (hoverResponse && hoverResponse.contents && Array.isArray(hoverResponse.contents)) {
      const stripeFullClassPath = Object.entries(hoverResponse.contents[0])
        .filter((item) => item[0] === 'value')
        .filter((item) => item[1].includes('com.stripe.model'));
      if (stripeFullClassPath.length > 0) {
        const stripeMethod = stripeFullClassPath[0][1].split(' ')[1].split('(')[0];
        const url = getJavaApiDocLink(stripeMethod);
        if (url) {
          stripeApiHoverContent = new MarkdownString(
            'See this method in the [Stripe API Reference](' + url + ')',
          );
          stripeApiHoverContent.isTrusted = true;
        }
      }
    }

    if (!!stripeApiHoverContent) {
      contents = contents.concat([stripeApiHoverContent]);
    }

    // get contributed hover commands from third party extensions.
    const contributedCommands: Command[] = await this.getContributedHoverCommands(params, token);

    if (contributedCommands.length > 0) {
      const contributedContent = new MarkdownString(
        contributedCommands.map((command) => this.convertCommandToMarkdown(command)).join(' | '),
      );
      contributedContent.isTrusted = true;
      contents = contents.concat([contributedContent]);
    }

    // combine all hover contents with java docs from server
    const serverHover = this.languageClient.protocol2CodeConverter.asHover(hoverResponse);
    if (serverHover && serverHover.contents) {
      contents = contents.concat(serverHover.contents);
      range = serverHover.range;
    }

    return new Hover(contents, range);
  }
Example #21
Source File: ALHoverProvider.ts    From vscode-alxmldocumentation with MIT License 5 votes vote down vote up
async provideHover(document: TextDocument, position: Position, token: CancellationToken) {   
        let result: MarkdownString = new MarkdownString();

        // retrieve source code from language server
        let alLangServerProxy = new ALLangServerProxy();     
        const alDefinition = await alLangServerProxy.GetALObjectFromDefinition(document.uri.toString(), position);
        if ((alDefinition === undefined) || (alDefinition.ALObject === null)) {
            return;
        }

        // find AL procedure by line no.
        let alProcedure: ALProcedure | undefined = alDefinition.ALObject.Procedures?.find(procedure => procedure.LineNo === alDefinition.Position.line);
        if ((alProcedure === undefined) || (alProcedure.ALDocumentation.Exists === ALDocumentationExists.No)) {
            return; // not found
        }

        let jsonDocumentation: any = await alDefinition.ALObject.GetDocumentationAsJsonObject(alProcedure);                
        // AL Language Version 6.x is providing simple XML Documentation capabilities. Do not push procedure summary in this case.
        if ((alLangServerProxy.GetALExtension()?.packageJSON.version < '6.0.0') || (alProcedure.ALDocumentation.Exists === ALDocumentationExists.Inherit)) {
            // add Summary to hover message.
            if ((jsonDocumentation.summary) && (jsonDocumentation.summary !== '')) {
                result.appendMarkdown(`${jsonDocumentation.summary} \n`);
            } else {
                return; // don't show w/o summary
            }
        }
        // add Remarks to hover message.
        if ((jsonDocumentation.remarks) && (jsonDocumentation.remarks.trim() !== '')) {
            result.appendMarkdown(`*${jsonDocumentation.remarks}*  \n`);
        } 

        // add Return to hover message.
        if ((alProcedure.Return !== undefined) && (alProcedure.Return.ALDocumentation.Exists === ALDocumentationExists.Yes)) {
            // convert XML Documentation to more readable JSON object.
            let returnDocumentation = ALDocCommentUtil.GetJsonFromALDocumentation(alProcedure.Return.ALDocumentation.Documentation);
            if ((returnDocumentation.returns) && (returnDocumentation.returns.trim() !== '')) {
                result.appendMarkdown(`${returnDocumentation.returns} \n`);
            }
        }
        
        // add Example to hover message.
        if (jsonDocumentation.example) {
            result.appendMarkdown(`#### Example \n`);
            result.appendMarkdown(`${jsonDocumentation.example.value} \n`);
            result.appendCodeblock(jsonDocumentation.example.code);
        }

        if (result.value !== '') {
            return new Hover(result);
        }
    }
Example #22
Source File: gcodeHoverProvider.ts    From vscode-gcode with MIT License 5 votes vote down vote up
provideHover(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<Hover> {
        const code = document.getText(document.getWordRangeAtPosition(position));
        const definition = this.dictionary.lookup(code);
        return definition == null ? null : new Hover(definition);
    }
Example #23
Source File: yaccMode.ts    From yash with MIT License 5 votes vote down vote up
export function getYACCMode(yaccLanguageService: YACCLanguageService): LanguageMode {
    const cache = CreateDocumentCache<YACCDocument>(10, 60, document => yaccLanguageService.parseYACCDocument(document));
    return {
        getId() {
            return 'yacc';
        },
        doValidation(document: TextDocument, force?:boolean): Diagnostic[] {
            if (force) {
                return yaccLanguageService.doValidation(document, yaccLanguageService.parseYACCDocument(document));
            }
            const yacc = cache.get(document);
            return yaccLanguageService.doValidation(document, yacc);
        },
        doComplete(document: TextDocument, position: Position): CompletionList | CompletionItem[] {
            const yacc = cache.get(document);
            return yaccLanguageService.doComplete(document, position, yacc);
        },
        doHover(document: TextDocument, position: Position): Hover | null {
            const yacc = cache.get(document);
            return yaccLanguageService.doHover(document, position, yacc);
        },
        findTypeDefinition(document: TextDocument, position: Position): Definition | null {
            const yacc = cache.get(document);
            return yaccLanguageService.findTypeDefinition(document, position, yacc);
        },
        findDefinition(document: TextDocument, position: Position): Definition | null {
            const yacc = cache.get(document);
            return yaccLanguageService.findDefinition(document, position, yacc);
        },
        findReferences(document: TextDocument, position: Position): Location[] {
            const yacc = cache.get(document);
            return yaccLanguageService.findReferences(document, position, yacc);
        },
        doRename(document: TextDocument, position: Position, newName: string): WorkspaceEdit | null {
            const yacc = cache.get(document);
            return yaccLanguageService.doRename(document, position, newName, yacc);
        },
        getSemanticTokens(document: TextDocument): SemanticTokenData[] {
            const yacc = cache.get(document);
            return yaccLanguageService.getSemanticTokens(document, yacc);
        },
        getSemanticTokenLegend() {
            return { types: tokenTypes, modifiers: tokenModifiers };
        },
        onDocumentRemoved(document: TextDocument) {
            cache.onDocumentRemoved(document);
        },
        dispose() {
            cache.dispose();
        }
    };
}
Example #24
Source File: yaccHover.ts    From yash with MIT License 5 votes vote down vote up
export function doYACCHover(document: TextDocument, position: Position, yaccDocument: YACCDocument): Hover | null {
    const offset = document.offsetAt(position);
    const code = yaccDocument.getEmbeddedNode(offset);
    if (code) {
        return null;
    }

    var symbol: ISymbol;
    const word = document.getText(document.getWordRangeAtPosition(position));
    const node = yaccDocument.getNodeByOffset(offset);
    if (node) {
        // Inside <...>
        if (node.typeOffset && offset > node.typeOffset) {
            if (!node.typeEnd || offset <= node.typeEnd) {
                if ((symbol = yaccDocument.types[word])) {
                    message = createMarkedCodeString(symbol.type, 'yacc');
                    return { contents: [createMarkedCodeString(symbol.type, 'yacc')] }
                }
                return null;
            }
        }
    }

    var message: MarkdownString | undefined = undefined;
    if ((symbol = yaccDocument.symbols[word])) {
        const config = workspace.getConfiguration('yash');
        const yyType = config.get('YYTYPE', '');
        const guess = yyType !== '' ? yyType : '?';
        message = createMarkedCodeString(`%type <${symbol.type ? symbol.type : guess}> ${symbol.name}`, 'yacc');
    } else if ((symbol = yaccDocument.tokens[word])) {
        const node = yaccDocument.getNodeByOffset(symbol.offset)!;
        const head = document.getText(document.getWordRangeAtPosition(document.positionAt(node!.offset + 1)));
        message = createMarkedCodeString(`%${head} <${symbol.type ? symbol.type : '?'}> ${symbol.name}`, 'yacc');
    } else if ((symbol = yaccDocument.aliases[`"${word}"`])) {
        if (symbol.alias) {
            symbol = symbol.alias;
            const node = yaccDocument.getNodeByOffset(symbol.offset)!;
            const head = document.getText(document.getWordRangeAtPosition(document.positionAt(node!.offset + 1)));
            message = createMarkedCodeString(`%${head} <${symbol.type ? symbol.type : '?'}> ${symbol.name}`, 'yacc');
        }
    } else if (predefined[word]) {
        message = createMarkedCodeString(predefined[word], 'yacc');
    }

    const namedReference = yaccDocument.namedReferences[`[${word}]`]
    if (namedReference) {
        if (namedReference.symbol) {
            message = createMarkedCodeString(`Named reference for ${namedReference.symbol}`, 'plaintext');
        } else {
            message = createMarkedCodeString(`Middle rule action reference`, 'plaintext');
        }
    }

    if (message)
        return { contents: [message] };

    return null;
}
Example #25
Source File: spDefineItem.ts    From sourcepawn-vscode with MIT License 5 votes vote down vote up
toHover(): Hover {
    return new Hover([
      { language: "sourcepawn", value: `#define ${this.name} ${this.value}` },
      descriptionToMD(this.description),
    ]);
  }
Example #26
Source File: spProviders.ts    From sourcepawn-vscode with MIT License 5 votes vote down vote up
public async provideHover(
    document: TextDocument,
    position: Position,
    token: CancellationToken
  ): Promise<Hover> {
    return hoverProvider(this.itemsRepository, document, position, token);
  }
Example #27
Source File: spVariableItem.ts    From sourcepawn-vscode with MIT License 5 votes vote down vote up
toHover(): Hover | undefined {
    if (this.type === "") {
      return undefined;
    }
    return new Hover([
      { language: "sourcepawn", value: `${this.type} ${this.name};` },
    ]);
  }
Example #28
Source File: spEnumMemberItem.ts    From sourcepawn-vscode with MIT License 5 votes vote down vote up
toHover(): Hover {
    let enumName = this.parent !== globalItem ? this.parent.name : "";
    return new Hover([
      { language: "sourcepawn", value: `${enumName} ${this.name};` },
      descriptionToMD(this.description),
    ]);
  }
Example #29
Source File: hoverProvider.ts    From vscode-todo-md with MIT License 4 votes vote down vote up
export function updateHover() {
	Global.hoverDisposable?.dispose();

	Global.hoverDisposable = languages.registerHoverProvider(
		getTodoMdFileDocumentSelector(),
		{
			provideHover(document, position, token) {
				const task = getTaskAtLineExtension(position.line);
				if (!task) {
					return undefined;
				}

				const range = getWordRangeAtPosition(document, position);
				const word = document.getText(range);
				/**
				 * Add hover description from the user setting "todomd.suggestItems".
				 */
				const hoveredWordUserDescription = new MarkdownString(undefined, true);
				hoveredWordUserDescription.isTrusted = true;
				/**
				 * Add all tasks with the same project/tag/context.
				 */
				const otherTasks: MarkdownString[] = [];

				if (range) {
					const parsedWord = parseWord(word, position.line, range.start.character);
					if (parsedWord.type === 'project') {
						const projectName = parsedWord.value;
						if ($state.suggestProjects[projectName]) {
							hoveredWordUserDescription.appendMarkdown($state.suggestProjects[projectName]);
						}

						for (const otherTask of $state.projectsForTreeView.find(project => project.title === projectName)?.tasks || []) {
							if (otherTask.lineNumber === task.lineNumber) {
								continue;
							}
							otherTasks.push(getTaskHoverMd(otherTask));
						}
					} else if (parsedWord.type === 'context') {
						const contextName = parsedWord.value;
						if ($state.suggestContexts[contextName]) {
							hoveredWordUserDescription.appendMarkdown($state.suggestContexts[contextName]);
						}

						for (const otherTask of $state.contextsForTreeView.find(context => context.title === contextName)?.tasks || []) {
							if (otherTask.lineNumber === task.lineNumber) {
								continue;
							}
							otherTasks.push(getTaskHoverMd(otherTask));
						}
					} else if (parsedWord.type === 'tags') {
						let index = 0;
						for (let i = 0; i < parsedWord.ranges.length; i++) {
							const tagRange = parsedWord.ranges[i];
							if (tagRange.contains(position)) {
								index = i;
								break;
							}
						}
						const tagName = parsedWord.value[index];

						if ($state.suggestTags[tagName]) {
							hoveredWordUserDescription.appendMarkdown($state.suggestTags[tagName]);
						}

						for (const otherTask of $state.tagsForTreeView.find(tag => tag.title === tagName)?.tasks || []) {
							if (otherTask.lineNumber === task.lineNumber) {
								continue;
							}
							otherTasks.push(getTaskHoverMd(otherTask));
						}
					}
				}
				return new Hover([
					hoveredWordUserDescription,
					getTaskHoverMd(task),
					...otherTasks,
				]);
			},
		},
	);
}