message: Sort line completions intelligently
diff: @@ -9,25 +9,80 @@ import { TextEditor } from './../textEditor';
  import { VimState } from '../state/vimState';
  import { Range } from '../common/motion/range';
  -const documents = v => {
  - return v.workspace.textDocuments;
  +const documentsStartingWith = (startingFileName, v) => {
  + return v.workspace.textDocuments.sort((a, b) => {
  + if (a.fileName === startingFileName) {
  + return -1;
  + } else if (b.fileName === startingFileName) {
  + return 1;
  + }
  + return 0;
  + });
  };
  -const lines = document => {
  - return document.getText().split('\n');
  +
  +const linesWithoutPadding = (
  + document: vscode.TextDocument,
  + startLine: number,
  + reverse: boolean
  +) => {
  + const distanceFromStartLine = (line: number) => {
  + let distance = reverse ? startLine - line : line - startLine;
  + if (distance < 0) {
  + // We prioritized any items in the main direction searched,
  + // but now find closest items in opposite direction.
  + distance = startLine + Math.abs(distance);
  + }
  +
  + return distance;
  };
  -const getCompletionsForText = (text: string): string[] | null => {
  +
  + return document
  + .getText()
  + .split('\n')
  + .map((text, line) => ({
  + distance: distanceFromStartLine(line),
  + text: text.replace(/^[ \t]*/, ''),
  + }))
  + .sort((a, b) => (a.distance > b.distance ? 1 : -1));
  +};
  +
  +/**
  + * Get all completions that match given text within open documents.
  + *
  + * Results are sorted in a few ways:
  + * 1) The current document is prioritized over other open documents.
  + * 2) For the current document, lines above the current cursor are always prioritized over lines below it.
  + * 3) For the current document, lines are also prioritized based on distance from cursor.
  + * 4) For other documents, lines are prioritized based on distance from the top.
  + *
  + * @param text - Text to partially match. Indentation is stripped.
  + * @param currentFileName - Current file, which is prioritized in sorting.
  + * @param currentPosition - Current position, which is prioritized when sorting for current file.
  + */
  +const getCompletionsForText = (
  + text: string,
  + currentFileName: string,
  + currentPosition: Position
  +): string[] | null => {
  const matchedLines: string[] = [];
  - for (const document of documents(vscode)) {
  - for (const line of lines(document)) {
  - const lineWithoutPadding = line.replace(/^[ \t]/, '');
  + for (const document of documentsStartingWith(currentFileName, vscode)) {
  + let startLine = 0;
  + let reverse = false;
  +
  + if (document.fileName === currentFileName) {
  + startLine = currentPosition.line;
  + reverse = true;
  + }
  +
  + for (const line of linesWithoutPadding(document, startLine, reverse)) {
  if (
  - matchedLines.indexOf(line) === -1 &&
  - lineWithoutPadding &&
  - lineWithoutPadding.startsWith(text) &&
  - lineWithoutPadding !== text
  + matchedLines.indexOf(line.text) === -1 &&
  + line.text &&
  + line.text.startsWith(text) &&
  + line.text !== text
  ) {
  - matchedLines.push(lineWithoutPadding);
  + matchedLines.push(line.text);
  }
  }
  }
  @@ -40,7 +95,7 @@ const getCompletionsForCurrentLine = (position: Position, vimState: VimState): s
  new vscode.Range(position.getFirstLineNonBlankChar(), vimState.cursorPosition)
  );
  - return getCompletionsForText(currentLineText);
  + return getCompletionsForText(currentLineText, vimState.editor.document.fileName, position);
  };
  export const lineCompletionProvider = {
  