Skip to content

Commit

Permalink
Get the TLDR Pages extension working again
Browse files Browse the repository at this point in the history
  • Loading branch information
sedwards2009 committed Apr 26, 2022
1 parent e83af40 commit 267057f
Show file tree
Hide file tree
Showing 18 changed files with 1,110 additions and 126 deletions.
14 changes: 0 additions & 14 deletions extensions/TLDRPages/build_scripts/download_data.js

This file was deleted.

14 changes: 14 additions & 0 deletions extensions/TLDRPages/build_scripts/download_data.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright 2020 Simon Edwards <[email protected]>
*
* This source code is licensed under the MIT license which is detailed in the LICENSE.txt file.
*/
import sh from 'shelljs';

if ( ! sh.test('-d', 'data')) {
sh.echo("Downloading TLDR Pages data files...");
sh.exec('download --extract --out data http://tldr-pages.github.io/assets/tldr.zip');
sh.rm('-r', 'data/pages.*');
sh.mv('data/index.json', 'data/pages/index.json');
sh.echo("Done downloading TLDR Pages data.");
}
File renamed without changes.
6 changes: 3 additions & 3 deletions extensions/TLDRPages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
"displayName": "TLDR Pages",
"version": "1.0.0",
"description": "",
"windowMain": "dist/main.js",
"type": "module",
"exports": "./dist/main.js",
"scripts": {
"build": "yarn run fetch-data && tsc",
"clean": "shx rm -rf dist data",
"fetch-data": "node build_scripts/download_data.js",
"fetch-data": "node build_scripts/download_data.mjs",
"test": "yarn run build && jest"
},
"author": "",
Expand All @@ -22,7 +23,6 @@
}
]
},
"isInternal": true,
"devDependencies": {
"@extraterm/extraterm-extension-api": "0.15.0",
"@types/jest": "27.0.1",
Expand Down
50 changes: 26 additions & 24 deletions extensions/TLDRPages/src/PageDatabase.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*
* Copyright 2020 Simon Edwards <[email protected]>
* Copyright 2022 Simon Edwards <[email protected]>
*
* This source code is licensed under the MIT license which is detailed in the LICENSE.txt file.
*/
import * as path from 'path';
import * as fs from 'fs';
import * as path from 'node:path';
import * as fs from 'node:fs';


export interface PageInfo {
Expand All @@ -29,15 +29,17 @@ enum ParseState {

export class PageDatabase {

private _commandNameList: string[] = [];
private _pageInfoList: PageInfo[] = [];
private _pageInfoCache = new Map<string, PageInfo>();
#commandNameList: string[] = [];
#pageInfoList: PageInfo[] = [];
#pageInfoCache = new Map<string, PageInfo>();
#databasePath: string;

constructor(private _databasePath: string) {
constructor(databasePath: string) {
this.#databasePath = databasePath;
}

async loadIndex(): Promise<void> {
const pagesIndexPath = path.join(this._databasePath, "index.json");
const pagesIndexPath = path.join(this.#databasePath, "index.json");
const indexJSONString = await fs.promises.readFile(pagesIndexPath, {encoding: "utf8"});
const pageIndex = JSON.parse(indexJSONString);

Expand Down Expand Up @@ -66,45 +68,45 @@ export class PageDatabase {
}
}
}
this._commandNameList = commandList;
this._pageInfoList = pageInfoList;
this.#commandNameList = commandList;
this.#pageInfoList = pageInfoList;
}

getCommandNames(): string[] {
return this._commandNameList;
return this.#commandNameList;
}

async getPageInfoByName(commandName: string, platform: string): Promise<PageInfo> {
const info = this._pageInfoList.find(info => info.command === commandName && info.platform === platform);
const info = this.#pageInfoList.find(info => info.command === commandName && info.platform === platform);
if (info == null) {
return null;
}
return this._getPageInfoByInfo(info);
return this.#getPageInfoByInfo(info);
}

async getPageInfoByIndex(commandIndex: number): Promise<PageInfo> {
const info = this._pageInfoList[commandIndex];
return this._getPageInfoByInfo(info);
const info = this.#pageInfoList[commandIndex];
return this.#getPageInfoByInfo(info);
}

private async _getPageInfoByInfo(commandInfo: PageInfo): Promise<PageInfo> {
if (this._pageInfoCache.has(commandInfo.name)) {
return this._pageInfoCache.get(commandInfo.name);
async #getPageInfoByInfo(commandInfo: PageInfo): Promise<PageInfo> {
if (this.#pageInfoCache.has(commandInfo.name)) {
return this.#pageInfoCache.get(commandInfo.name);
}
await this._fillInExamples(commandInfo);
this._pageInfoCache.set(commandInfo.name, commandInfo);
await this.#fillInExamples(commandInfo);
this.#pageInfoCache.set(commandInfo.name, commandInfo);
return commandInfo;
}

private async _fillInExamples(commandInfo: PageInfo): Promise<void> {
const pagePath = path.join(this._databasePath, commandInfo.platform, `${commandInfo.name}.md`);
async #fillInExamples(commandInfo: PageInfo): Promise<void> {
const pagePath = path.join(this.#databasePath, commandInfo.platform, `${commandInfo.name}.md`);
const pageString = await fs.promises.readFile(pagePath, { encoding: "utf8" });
const {description, examples } = this._parsePage(pageString);
const {description, examples } = this.#parsePage(pageString);
commandInfo.description = description;
commandInfo.examples = examples;
}

private _parsePage(pageString: string): { description: string; examples: CommandExample[]; } {
#parsePage(pageString: string): { description: string; examples: CommandExample[]; } {
const lines = pageString.split("\n");
let state: ParseState = ParseState.PROLOGUE;

Expand Down
13 changes: 6 additions & 7 deletions extensions/TLDRPages/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/*
* Copyright 2020 Simon Edwards <[email protected]>
* Copyright 2022 Simon Edwards <[email protected]>
*
* This source code is licensed under the MIT license which is detailed in the LICENSE.txt file.
*/
import { ExtensionContext, Logger, ListPickerOptions } from '@extraterm/extraterm-extension-api';
import * as path from 'path';
import * as fs from 'fs';
import { PageDatabase } from './PageDatabase';
import * as path from 'node:path';
import { PageDatabase } from './PageDatabase.js';


let log: Logger = null;
Expand All @@ -30,7 +29,7 @@ async function showCommandList(): Promise<void> {
selectedItemIndex: 0,
};

const selected = await context.window.activeTerminal.tab.showListPicker(allCommandsOptions);
const selected = await context.activeTerminal.tab.showListPicker(allCommandsOptions);
if (selected == null) {
return;
}
Expand All @@ -42,9 +41,9 @@ async function showCommandList(): Promise<void> {
items: info.examples.map(ex => ex.description),
selectedItemIndex: 0,
};
const selectedExample = await context.window.activeTerminal.tab.showListPicker(commandOptions);
const selectedExample = await context.activeTerminal.tab.showListPicker(commandOptions);
if (selectedExample == null) {
return;
}
context.window.activeTerminal.type(info.examples[selectedExample].commandLine);
context.activeTerminal.type(info.examples[selectedExample].commandLine);
}
15 changes: 2 additions & 13 deletions extensions/TLDRPages/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"noImplicitAny": false,
"noImplicitReturns": true,
"noImplicitThis": true,
"noLib": false,
"outDir": "dist",
"removeComments": false,
"rootDir": "src",
"sourceMap": true,
"target": "es2020"
"rootDir": "src"
},
"include": [
"./src/**/*.ts"
Expand Down
41 changes: 11 additions & 30 deletions main/src/CommandPalette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,43 @@
*/
import { Logger, log, getLogger } from "extraterm-logging";
import { doLater } from "extraterm-timeoutqt";
import { Direction, QWidget, WidgetAttribute, WindowType } from "@nodegui/nodegui";
import { BoxLayout, Widget, Label } from "qt-construct";
import { Label } from "qt-construct";
import { Tab } from "./Tab.js";
import { Window } from "./Window.js";
import { ExtensionManager } from "./InternalTypes.js";
import { KeybindingsIOManager } from "./keybindings/KeybindingsIOManager.js";
import { Entry, FieldType, ListPicker } from "./ui/ListPicker.js";
import { UiStyle } from "./ui/UiStyle.js";
import { WindowPopOver } from "./ui/WindowPopOver.js";


export class CommandPalette {
private _log: Logger = null;
#uiStyle: UiStyle = null;

#extensionManager: ExtensionManager = null;
#keybindingsIOManager: KeybindingsIOManager = null;
#listPicker: ListPicker = null;
#popUp: QWidget = null;
#windowPopOver: WindowPopOver = null;

constructor(extensionManager: ExtensionManager, keybindingsIOManager: KeybindingsIOManager, uiStyle: UiStyle) {
this._log = getLogger("CommandPalette", this);
this.#uiStyle = uiStyle;
this.#extensionManager = extensionManager;
this.#keybindingsIOManager = keybindingsIOManager;

this.#createPopUp();
this.#createPopOver();
}

#createPopUp(): void {
#createPopOver(): void {
this.#listPicker = new ListPicker(this.#uiStyle);

this.#popUp = Widget({
cssClass: ["list-picker"],
windowFlag: WindowType.Popup,
attribute: [WidgetAttribute.WA_WindowPropagation, WidgetAttribute.WA_X11NetWmWindowTypePopupMenu],
layout: BoxLayout({
direction: Direction.TopToBottom,
children: [
Label({text: "Command Palette"}),
this.#listPicker.getWidget()
]
})
});
this.#windowPopOver = new WindowPopOver([
Label({text: "Command Palette"}),
this.#listPicker.getWidget()
]);
this.#listPicker.onSelected((id: string) => this.#commandSelected(id));
}

show(window: Window, tab: Tab): void {
this.#popUp.setNodeParent(window.getWidget());

const commands = this.#extensionManager.queryCommands({
commandPalette: true,
categories: ["application", "window", "terminal", "viewer"],
Expand All @@ -77,19 +65,12 @@ export class CommandPalette {

this.#listPicker.setEntries([FieldType.ICON_NAME, FieldType.TEXT, FieldType.SECONDARY_TEXT_RIGHT], entries);

const tabRect = window.getTabGlobalGeometry(tab);

const width = 500; // px TODO: make it respect DPI
const leftOffset = (tabRect.width() - width ) /2;

this.#popUp.setGeometry(tabRect.left() + leftOffset, tabRect.top(), width, tabRect.height());
this.#popUp.raise();
this.#popUp.show();
this.#windowPopOver.show(window, tab);
this.#listPicker.focus();
}

hide(): void {
this.#popUp.hide();
this.#windowPopOver.hide();
}

#commandSelected(id: string): void {
Expand Down
1 change: 1 addition & 0 deletions main/src/InternalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export interface ExtensionManager {
createSessionEditor(sessionType: string, sessionConfiguration: ExtensionApi.SessionConfiguration): InternalSessionEditor;
createSessionSettingsEditors(sessionType: string, sessionConfiguration: ExtensionApi.SessionConfiguration,
window: Window): InternalSessionSettingsEditor[];
showListPicker(tab: Tab, options: ExtensionApi.ListPickerOptions): Promise<number>;

// setViewerTabDisplay(viewerTabDisplay: ViewerTabDisplay): void;
// getViewerTabDisplay(): ViewerTabDisplay;
Expand Down
15 changes: 14 additions & 1 deletion main/src/extension/ExtensionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { LineRangeChange, Terminal } from "../terminal/Terminal.js";
import { InternalExtensionContext, InternalSessionEditor, InternalSessionSettingsEditor } from "../InternalTypes.js";
import { InternalExtensionContextImpl } from "./InternalExtensionContextImpl.js";
import { Tab } from "../Tab.js";
import { ListPickerPopOver } from "./ListPickerPopOver.js";
import { UiStyle } from "../ui/UiStyle.js";


interface ActiveExtension {
Expand All @@ -49,6 +51,7 @@ export class ExtensionManager implements InternalTypes.ExtensionManager {
private _log: Logger = null;

#configDatabase: ConfigDatabase = null;
#uiStyle: UiStyle = null;

#extensionMetadata: ExtensionMetadata[] = [];
#desiredState: ExtensionDesiredState = null;
Expand All @@ -71,11 +74,14 @@ export class ExtensionManager implements InternalTypes.ExtensionManager {

#allWindows: Window[] = [];

constructor(configDatabase: ConfigDatabase, extensionPaths: string[],
#listPickerPopOver: ListPickerPopOver = null;

constructor(configDatabase: ConfigDatabase, uiStyle: UiStyle, extensionPaths: string[],
applicationVersion: string) {

this._log = getLogger("ExtensionManager", this);
this.#configDatabase = configDatabase;
this.#uiStyle = uiStyle;

this.#extensionPaths = extensionPaths;
this.onDesiredStateChanged = this.#desiredStateChangeEventEmitter.event;
Expand Down Expand Up @@ -749,4 +755,11 @@ export class ExtensionManager implements InternalTypes.ExtensionManager {
getAllWindows(): Window[] {
return this.#allWindows;
}

async showListPicker(tab: Tab, options: ExtensionApi.ListPickerOptions): Promise<number> {
if (this.#listPickerPopOver == null) {
this.#listPickerPopOver = new ListPickerPopOver(this.#uiStyle);
}
return this.#listPickerPopOver.show(this.getWindowForTab(tab), tab, options);
}
}
3 changes: 1 addition & 2 deletions main/src/extension/InternalExtensionContextImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { LineRangeChange, Terminal } from "../terminal/Terminal.js";
import { CommandsRegistry } from "../CommandsRegistry.js";
import { WorkspaceSessionEditorRegistry } from "./WorkspaceSessionEditorRegistry.js";
import { TerminalImpl } from "./api/TerminalImpl.js";
import { Block } from "../terminal/Block.js";
import { BlockImpl } from "./api/BlockImpl.js";
import { BlockFrame } from "../terminal/BlockFrame.js";
import { TabImpl } from "./api/TabImpl.js";
Expand Down Expand Up @@ -171,7 +170,7 @@ export class InternalExtensionContextImpl implements InternalExtensionContext {
}

async showListPicker(tab: Tab, options: ExtensionApi.ListPickerOptions): Promise<number> {
throw new Error("Method not implemented.");
return this.#extensionManager.showListPicker(tab, options);
}

terminalEnvironmentChanged(terminal: Terminal, changeList: string[]): void {
Expand Down
Loading

0 comments on commit 267057f

Please sign in to comment.