mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Remove reliance on document.lineAt (#154191)
* Remove reliance on document.lineAt This helps aligning more with the LSP types: https://github.com/microsoft/vscode-languageserver-node/issues/146 * Strip newline
This commit is contained in:
parent
510a74fc2c
commit
fc0bd9d377
|
@ -9,7 +9,7 @@ import * as uri from 'vscode-uri';
|
|||
import { OpenDocumentLinkCommand } from '../commands/openDocumentLink';
|
||||
import { ILogger } from '../logging';
|
||||
import { IMdParser } from '../markdownEngine';
|
||||
import { ITextDocument } from '../types/textDocument';
|
||||
import { getLine, ITextDocument } from '../types/textDocument';
|
||||
import { coalesce } from '../util/arrays';
|
||||
import { noopToken } from '../util/cancellation';
|
||||
import { Disposable } from '../util/dispose';
|
||||
|
@ -422,9 +422,9 @@ export class MdLinkComputer {
|
|||
reference = match[5];
|
||||
const offset = ((match.index ?? 0) + match[1].length) + 1;
|
||||
hrefStart = document.positionAt(offset);
|
||||
const line = document.lineAt(hrefStart.line);
|
||||
const line = getLine(document, hrefStart.line);
|
||||
// See if link looks like a checkbox
|
||||
const checkboxMatch = line.text.match(/^\s*[\-\*]\s*\[x\]/i);
|
||||
const checkboxMatch = line.match(/^\s*[\-\*]\s*\[x\]/i);
|
||||
if (checkboxMatch && hrefStart.character <= checkboxMatch[0].length) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ import type Token = require('markdown-it/lib/token');
|
|||
import * as vscode from 'vscode';
|
||||
import { IMdParser } from '../markdownEngine';
|
||||
import { MdTableOfContentsProvider } from '../tableOfContents';
|
||||
import { ITextDocument } from '../types/textDocument';
|
||||
import { getLine, ITextDocument } from '../types/textDocument';
|
||||
import { isEmptyOrWhitespace } from '../util/string';
|
||||
|
||||
const rangeLimit = 5000;
|
||||
|
||||
|
@ -59,7 +60,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider {
|
|||
const toc = await this.tocProvide.getForDocument(document);
|
||||
return toc.entries.map(entry => {
|
||||
let endLine = entry.sectionLocation.range.end.line;
|
||||
if (document.lineAt(endLine).isEmptyOrWhitespace && endLine >= entry.line + 1) {
|
||||
if (isEmptyOrWhitespace(getLine(document, endLine)) && endLine >= entry.line + 1) {
|
||||
endLine = endLine - 1;
|
||||
}
|
||||
return new vscode.FoldingRange(entry.line, endLine);
|
||||
|
@ -72,7 +73,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider {
|
|||
return multiLineListItems.map(listItem => {
|
||||
const start = listItem.map[0];
|
||||
let end = listItem.map[1] - 1;
|
||||
if (document.lineAt(end).isEmptyOrWhitespace && end >= start + 1) {
|
||||
if (isEmptyOrWhitespace(getLine(document, end)) && end >= start + 1) {
|
||||
end = end - 1;
|
||||
}
|
||||
return new vscode.FoldingRange(start, end, this.getFoldingRangeKind(listItem));
|
||||
|
|
|
@ -7,7 +7,7 @@ import { dirname, resolve } from 'path';
|
|||
import * as vscode from 'vscode';
|
||||
import { IMdParser } from '../markdownEngine';
|
||||
import { TableOfContents } from '../tableOfContents';
|
||||
import { ITextDocument } from '../types/textDocument';
|
||||
import { getLine, ITextDocument } from '../types/textDocument';
|
||||
import { resolveUriToMarkdownFile } from '../util/openDocumentLink';
|
||||
import { Schemes } from '../util/schemes';
|
||||
import { IMdWorkspace } from '../workspace';
|
||||
|
@ -167,7 +167,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv
|
|||
private readonly definitionPattern = /^\s*\[[\w\-]+\]:\s*([^\s]*)$/m;
|
||||
|
||||
private getPathCompletionContext(document: ITextDocument, position: vscode.Position): CompletionContext | undefined {
|
||||
const line = document.lineAt(position.line).text;
|
||||
const line = getLine(document, position.line);
|
||||
|
||||
const linePrefixText = line.slice(0, position.character);
|
||||
const lineSuffixText = line.slice(position.character);
|
||||
|
|
|
@ -6,7 +6,8 @@ import Token = require('markdown-it/lib/token');
|
|||
import * as vscode from 'vscode';
|
||||
import { IMdParser } from '../markdownEngine';
|
||||
import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents';
|
||||
import { ITextDocument } from '../types/textDocument';
|
||||
import { getLine, ITextDocument } from '../types/textDocument';
|
||||
import { isEmptyOrWhitespace } from '../util/string';
|
||||
|
||||
interface MarkdownItTokenWithMap extends Token {
|
||||
map: [number, number];
|
||||
|
@ -111,14 +112,14 @@ function createBlockRange(block: MarkdownItTokenWithMap, document: ITextDocument
|
|||
if (block.type === 'fence') {
|
||||
return createFencedRange(block, cursorLine, document, parent);
|
||||
} else {
|
||||
let startLine = document.lineAt(block.map[0]).isEmptyOrWhitespace ? block.map[0] + 1 : block.map[0];
|
||||
let startLine = isEmptyOrWhitespace(getLine(document, block.map[0])) ? block.map[0] + 1 : block.map[0];
|
||||
let endLine = startLine === block.map[1] ? block.map[1] : block.map[1] - 1;
|
||||
if (block.type === 'paragraph_open' && block.map[1] - block.map[0] === 2) {
|
||||
startLine = endLine = cursorLine;
|
||||
} else if (isList(block) && document.lineAt(endLine).isEmptyOrWhitespace) {
|
||||
} else if (isList(block) && isEmptyOrWhitespace(getLine(document, endLine))) {
|
||||
endLine = endLine - 1;
|
||||
}
|
||||
const range = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text?.length ?? 0);
|
||||
const range = new vscode.Range(startLine, 0, endLine, getLine(document, endLine).length);
|
||||
if (parent?.range.contains(range) && !parent.range.isEqual(range)) {
|
||||
return new vscode.SelectionRange(range, parent);
|
||||
} else if (parent?.range.isEqual(range)) {
|
||||
|
@ -130,7 +131,7 @@ function createBlockRange(block: MarkdownItTokenWithMap, document: ITextDocument
|
|||
}
|
||||
|
||||
function createInlineRange(document: ITextDocument, cursorPosition: vscode.Position, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined {
|
||||
const lineText = document.lineAt(cursorPosition.line).text;
|
||||
const lineText = getLine(document, cursorPosition.line);
|
||||
const boldSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, parent);
|
||||
const italicSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, parent);
|
||||
let comboSelection: vscode.SelectionRange | undefined;
|
||||
|
@ -150,8 +151,8 @@ function createFencedRange(token: MarkdownItTokenWithMap, cursorLine: number, do
|
|||
const startLine = token.map[0];
|
||||
const endLine = token.map[1] - 1;
|
||||
const onFenceLine = cursorLine === startLine || cursorLine === endLine;
|
||||
const fenceRange = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text.length);
|
||||
const contentRange = endLine - startLine > 2 && !onFenceLine ? new vscode.Range(startLine + 1, 0, endLine - 1, document.lineAt(endLine - 1).text.length) : undefined;
|
||||
const fenceRange = new vscode.Range(startLine, 0, endLine, getLine(document, endLine).length);
|
||||
const contentRange = endLine - startLine > 2 && !onFenceLine ? new vscode.Range(startLine + 1, 0, endLine - 1, getLine(document, endLine - 1).length) : undefined;
|
||||
if (contentRange) {
|
||||
return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(fenceRange, parent));
|
||||
} else {
|
||||
|
@ -242,7 +243,7 @@ function getFirstChildHeader(document: ITextDocument, header?: TocEntry, toc?: r
|
|||
const children = toc.filter(t => header.sectionLocation.range.contains(t.sectionLocation.range) && t.sectionLocation.range.start.line > header.sectionLocation.range.start.line).sort((t1, t2) => t1.line - t2.line);
|
||||
if (children.length > 0) {
|
||||
childRange = children[0].sectionLocation.range.start;
|
||||
const lineText = document.lineAt(childRange.line - 1).text;
|
||||
const lineText = getLine(document, childRange.line - 1);
|
||||
return childRange ? childRange.translate(-1, lineText.length) : undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import * as vscode from 'vscode';
|
|||
import { ILogger } from './logging';
|
||||
import { IMdParser } from './markdownEngine';
|
||||
import { githubSlugifier, Slug, Slugifier } from './slugify';
|
||||
import { ITextDocument } from './types/textDocument';
|
||||
import { getLine, ITextDocument } from './types/textDocument';
|
||||
import { Disposable } from './util/dispose';
|
||||
import { isMarkdownFile } from './util/file';
|
||||
import { Schemes } from './util/schemes';
|
||||
|
@ -108,9 +108,9 @@ export class TableOfContents {
|
|||
}
|
||||
|
||||
const lineNumber = heading.map[0];
|
||||
const line = document.lineAt(lineNumber);
|
||||
const line = getLine(document, lineNumber);
|
||||
|
||||
let slug = parser.slugifier.fromHeading(line.text);
|
||||
let slug = parser.slugifier.fromHeading(line);
|
||||
const existingSlugEntry = existingSlugEntries.get(slug.value);
|
||||
if (existingSlugEntry) {
|
||||
++existingSlugEntry.count;
|
||||
|
@ -120,14 +120,14 @@ export class TableOfContents {
|
|||
}
|
||||
|
||||
const headerLocation = new vscode.Location(document.uri,
|
||||
new vscode.Range(lineNumber, 0, lineNumber, line.text.length));
|
||||
new vscode.Range(lineNumber, 0, lineNumber, line.length));
|
||||
|
||||
const headerTextLocation = new vscode.Location(document.uri,
|
||||
new vscode.Range(lineNumber, line.text.match(/^#+\s*/)?.[0].length ?? 0, lineNumber, line.text.length - (line.text.match(/\s*#*$/)?.[0].length ?? 0)));
|
||||
new vscode.Range(lineNumber, line.match(/^#+\s*/)?.[0].length ?? 0, lineNumber, line.length - (line.match(/\s*#*$/)?.[0].length ?? 0)));
|
||||
|
||||
toc.push({
|
||||
slug,
|
||||
text: TableOfContents.getHeaderText(line.text),
|
||||
text: TableOfContents.getHeaderText(line),
|
||||
level: TableOfContents.getHeaderLevel(heading.markup),
|
||||
line: lineNumber,
|
||||
sectionLocation: headerLocation, // Populated in next steps
|
||||
|
@ -151,7 +151,7 @@ export class TableOfContents {
|
|||
sectionLocation: new vscode.Location(document.uri,
|
||||
new vscode.Range(
|
||||
entry.sectionLocation.range.start,
|
||||
new vscode.Position(endLine, document.lineAt(endLine).text.length)))
|
||||
new vscode.Position(endLine, getLine(document, endLine).length)))
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import { nulLogger } from './nulLogging';
|
|||
import { assertRangeEqual, joinLines, workspacePath } from './util';
|
||||
|
||||
|
||||
suite.only('Markdown: MdLinkComputer', () => {
|
||||
suite('Markdown: MdLinkComputer', () => {
|
||||
|
||||
function getLinksForFile(fileContents: string): Promise<MdLink[]> {
|
||||
const doc = new InMemoryDocument(workspacePath('x.md'), fileContents);
|
||||
|
|
|
@ -3,15 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type * as vscode from 'vscode';
|
||||
|
||||
/**
|
||||
* Minimal version of {@link vscode.TextLine}.
|
||||
*/
|
||||
export interface ITextLine {
|
||||
readonly text: string;
|
||||
readonly isEmptyOrWhitespace: boolean;
|
||||
}
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
/**
|
||||
* Minimal version of {@link vscode.TextDocument}.
|
||||
|
@ -22,6 +14,9 @@ export interface ITextDocument {
|
|||
readonly lineCount: number;
|
||||
|
||||
getText(range?: vscode.Range): string;
|
||||
lineAt(line: number): ITextLine;
|
||||
positionAt(offset: number): vscode.Position;
|
||||
}
|
||||
|
||||
export function getLine(doc: ITextDocument, line: number): string {
|
||||
return doc.getText(new vscode.Range(line, 0, line, Number.MAX_VALUE)).replace(/\r?\n$/, '');
|
||||
}
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
|
||||
import * as vscode from 'vscode';
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import { ITextDocument, ITextLine } from '../types/textDocument';
|
||||
import { ITextDocument } from '../types/textDocument';
|
||||
|
||||
export class InMemoryDocument implements ITextDocument {
|
||||
|
||||
private readonly _doc: TextDocument;
|
||||
|
||||
private lines: ITextLine[] | undefined;
|
||||
|
||||
constructor(
|
||||
public readonly uri: vscode.Uri, contents: string,
|
||||
public readonly version = 0,
|
||||
|
@ -25,16 +23,6 @@ export class InMemoryDocument implements ITextDocument {
|
|||
return this._doc.lineCount;
|
||||
}
|
||||
|
||||
lineAt(index: any): ITextLine {
|
||||
if (!this.lines) {
|
||||
this.lines = this._doc.getText().split(/\r?\n/).map(text => ({
|
||||
text,
|
||||
get isEmptyOrWhitespace() { return /^\s*$/.test(text); }
|
||||
}));
|
||||
}
|
||||
return this.lines[index];
|
||||
}
|
||||
|
||||
positionAt(offset: number): vscode.Position {
|
||||
const pos = this._doc.positionAt(offset);
|
||||
return new vscode.Position(pos.line, pos.character);
|
||||
|
|
8
extensions/markdown-language-features/src/util/string.ts
Normal file
8
extensions/markdown-language-features/src/util/string.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function isEmptyOrWhitespace(str: string): boolean {
|
||||
return /^\s*$/.test(str);
|
||||
}
|
Loading…
Reference in a new issue