Skip to content

Code vision ​

Rows above each declaration that say how often it is used and who wrote it. A press on the usages opens a peek of the references; a press on the authors opens CodeAuthorsCard.

tsx
import { useCallback } from 'react';
import { splitLines } from '@adecore/merge';
import type { Editor } from '@adecore/editor';
import type { EditorLanguage, GitBlameResult } from '@adecore/editor-react';
import type { FakeLanguageService } from '@adecore/editor-react/testing';
import { LanguageFrame } from '../shared/editor-frame.tsx';
import { SAMPLE, useDemoLanguage } from '../shared/editor.ts';
import { respondNavigation, respondSymbols } from '../shared/order-service.ts';

function configure(service: FakeLanguageService): void {
    respondSymbols(service);
    respondNavigation(service);
}

const DAY = 24 * 60 * 60 * 1000;

/* What `git blame` would say about the file on disk: two commits, the second of which wrote the last function. */
const BLAME: GitBlameResult = {
    commits: [
        { hash: 'a1b2c3d4e5', shortHash: 'a1b2c3d', author: 'Ada Lovelace', email: 'ada@example.com', at: Date.now() - 30 * DAY, summary: 'Add order totals' },
        { hash: 'f6e5d4c3b2', shortHash: 'f6e5d4c', author: 'Grace Hopper', email: 'grace@example.com', at: Date.now() - 2 * DAY, summary: 'Describe an order' }
    ],
    lines: splitLines(SAMPLE).map((_line, index) => (index >= 10 ? 1 : 0))
};

export default function CodeVisionDemo() {
    const { project, onMount } = useDemoLanguage(configure);

    const mount = useCallback(
        (editor: Editor, language: EditorLanguage | null) => {
            language?.codeVision.configure({ usages: true, authors: true });
            language?.codeVision.setBlame({ kind: 'ready', blame: BLAME, base: SAMPLE });
            return onMount(editor, language);
        },
        [onMount]
    );

    return (
        <LanguageFrame
            project={project}
            onMount={mount}
            toolbar={<span className="px-1 text-xs text-text-muted">Press the authors above a function, or its usages.</span>}
        />
    );
}

Both kinds are off until the app turns them on:

ts
language.codeVision.configure({ usages: true, authors: true });

Usages come from textDocument/references for the declarations in view plus 40 lines around them, three requests at a time, after the text and the scroll have settled. Declarations are read from the document's symbols. A count stays on its row until a new one is in.

Authors come from Git, which the package never runs. The app runs git blame on the file as it is on disk and hands over the result with that text, the base:

ts
language.codeVision.setBlame({ kind: 'pending' }); // holds the rows' height while Git runs
language.codeVision.setBlame({ kind: 'ready', blame, base: textOnDisk, openCommit: (hash) => showCommit(hash) });

A GitBlameResult has the commits (hash, shortHash, author, email, at in milliseconds, summary) and lines, the index of the commit of each line of base. omitted: 'untracked' or 'too-large' says why there is none. Lines typed since the blame map onto no commit and count as uncommitted, through mapBlame. setBlame(null) removes the authors.

CodeAuthorsCard lists the authors of the declaration by the number of lines they wrote, the uncommitted lines, and the latest commit, with a button to it when openCommit is set.

Files of more than 20,000 lines, or with more than 3,000 declarations (MAX_DECLARATIONS), get no rows.

Licenses and third-party notices are listed in each package.