From 3bb7b024b97eb42598301d375333d01796a7df55 Mon Sep 17 00:00:00 2001 From: felix Date: Sun, 5 Jul 2020 03:17:12 -0400 Subject: [PATCH 1/7] Made 'edit headline' hover icon removable. Added keybindings to switch focus with tab, ctrl+t and more --- CHANGELOG.md | 5 ++ leoInteg.leo | 3 +- leobridgeserver.py | 3 +- package.json | 107 ++++++++++++++++++++++++++--------- src/config.ts | 10 ++++ src/constants.ts | 8 +++ src/extension.ts | 3 +- src/leoIntegration.ts | 18 +++++- src/types.d.ts | 2 + src/webviews/apps/index.html | 28 ++++++++- 10 files changed, 150 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cceb462f..6bb08da5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## 0.1.13 + +- Added support for precise focus placement, focus switch between tree/body. +- Added commands and keybindings for 'goto' operations and other commands. + ## 0.1.12 - Added support for multiple opened files along with the 'new', 'Close', 'Save-As' commands. diff --git a/leoInteg.leo b/leoInteg.leo index 5d29c17a..cc46cf26 100644 --- a/leoInteg.leo +++ b/leoInteg.leo @@ -168,8 +168,7 @@ To contribute, see the official issues page for current list of 'TODO's at https # and so this now app.commanders() yields this: return [f.c for f in g.app.windowList] # did this add to existing array of g.app.commanders() ? - # print(str(self.g.app.commanders())) # test - print(*self.g.app.commanders(), sep='\n') + # print(*self.g.app.commanders(), sep='\n') if self.commander: self.commander.closed = False diff --git a/leobridgeserver.py b/leobridgeserver.py index edaa6a77..b26b1517 100644 --- a/leobridgeserver.py +++ b/leobridgeserver.py @@ -592,8 +592,7 @@ def openFile(self, p_file): # and so this now app.commanders() yields this: return [f.c for f in g.app.windowList] # did this add to existing array of g.app.commanders() ? - # print(str(self.g.app.commanders())) # test - print(*self.g.app.commanders(), sep='\n') + # print(*self.g.app.commanders(), sep='\n') if self.commander: self.commander.closed = False diff --git a/package.json b/package.json index c0dbf67c..0d6b6c3e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "leointeg", "displayName": "Leo Editor Integration with Visual Studio Code", "description": "Use Leo, the literate editor with outline, directly in vscode.", - "version": "0.1.12", + "version": "0.1.13", "author": { "name": "FĂ©lix" }, @@ -71,6 +71,12 @@ "Ignore All" ] }, + "leoIntegration.leoTreeBrowse": { + "scope": "application", + "default": false, + "type": "boolean", + "description": "Specifies whether to use Leo's style of tree browsing with the arrow keys" + }, "leoIntegration.treeKeepFocus": { "scope": "application", "default": true, @@ -107,6 +113,12 @@ "type": "boolean", "description": "Offer 'Open to the Side' in nodes context menu" }, + "leoIntegration.showEditOnNodes": { + "scope": "application", + "default": true, + "type": "boolean", + "description": "Shows 'Edit Headline' button on tree nodes" + }, "leoIntegration.showArrowsOnNodes": { "scope": "application", "default": false, @@ -267,7 +279,12 @@ { "command": "leointeg.showBody", "category": "Leo", - "title": "Show Body Pane" + "title": "Focus to Body" + }, + { + "command": "leointeg.showOutline", + "category": "Leo", + "title": "Focus to Tree" }, { "command": "leointeg.showLogPane", @@ -1100,6 +1117,10 @@ "command": "leointeg.showBody", "when": "false" }, + { + "command": "leointeg.showOutline", + "when": "false" + }, { "command": "leointeg.refreshFromDiskSelectionFromOutline", "when": "false" @@ -1323,7 +1344,7 @@ }, { "command": "leointeg.editHeadline", - "when": "viewItem =~ /leoNode/", + "when": "showEditOnNodes && viewItem =~ /leoNode/", "group": "inline@1" }, { @@ -1418,27 +1439,57 @@ }, { "command": "leointeg.insertNode", - "when": "leoTreeOpened", + "when": "leoTreeOpened && viewItem =~ /leoNode/", "group": "leoNodeContext3@1" }, { "command": "leointeg.cloneNode", - "when": "leoTreeOpened", + "when": "leoTreeOpened && viewItem =~ /leoNode/", "group": "leoNodeContext3@2" }, { "command": "leointeg.promote", - "when": "leoTreeOpened", + "when": "leoTreeOpened && viewItem =~ /leoNode/", "group": "leoNodeContext3@3" }, { "command": "leointeg.demote", - "when": "leoTreeOpened", + "when": "leoTreeOpened && viewItem =~ /leoNode/", "group": "leoNodeContext3@4" } ] }, "keybindings": [ + { + "command": "leointeg.showOutline", + "key": "alt+t", + "mac": "alt+t", + "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + }, + { + "command": "leointeg.showOutline", + "key": "ctrl+t", + "mac": "ctrl+t", + "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + }, + { + "command": "leointeg.showBody", + "key": "ctrl+t", + "mac": "ctrl+t", + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.showBody", + "key": "alt+d", + "mac": "alt+d", + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.showBody", + "key": "tab", + "mac": "tab", + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, { "command": "leointeg.executeScriptSelection", "key": "ctrl+b", @@ -1449,7 +1500,7 @@ "command": "leointeg.executeScriptSelection", "key": "ctrl+b", "mac": "ctrl+b", - "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.contractAll", @@ -1461,7 +1512,7 @@ "command": "leointeg.contractAllFromOutline", "key": "alt+-", "mac": "alt+-", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.editSelectedHeadline", @@ -1473,7 +1524,7 @@ "command": "leointeg.editSelectedHeadlineFromOutline", "key": "ctrl+h", "mac": "cmd+h", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.markSelection", @@ -1485,7 +1536,7 @@ "command": "leointeg.markSelectionFromOutline", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && !leoNodeMarked && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !leoNodeMarked && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.unmarkSelection", @@ -1497,7 +1548,7 @@ "command": "leointeg.unmarkSelectionFromOutline", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && leoNodeMarked && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && leoNodeMarked && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.promoteSelection", @@ -1513,7 +1564,7 @@ "win": "ctrl+oem_4", "linux": "ctrl+[", "mac": "cmd+[BracketLeft]", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.demoteSelection", @@ -1529,7 +1580,7 @@ "win": "ctrl+oem_6", "linux": "ctrl+]", "mac": "cmd+[BracketRight]", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineDownSelection", @@ -1541,7 +1592,7 @@ "command": "leointeg.moveOutlineDownSelectionFromOutline", "key": "ctrl+d", "mac": "cmd+d", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineLeftSelection", @@ -1553,7 +1604,7 @@ "command": "leointeg.moveOutlineLeftSelectionFromOutline", "key": "ctrl+l", "mac": "cmd+l", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineRightSelection", @@ -1565,7 +1616,7 @@ "command": "leointeg.moveOutlineRightSelectionFromOutline", "key": "ctrl+r", "mac": "cmd+r", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineUpSelection", @@ -1577,7 +1628,7 @@ "command": "leointeg.moveOutlineUpSelectionFromOutline", "key": "ctrl+u", "mac": "cmd+u", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineDownSelection", @@ -1589,7 +1640,7 @@ "command": "leointeg.moveOutlineDownSelectionFromOutline", "key": "shift+alt+down", "mac": "shift+alt+down", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineLeftSelection", @@ -1601,7 +1652,7 @@ "command": "leointeg.moveOutlineLeftSelectionFromOutline", "key": "shift+alt+left", "mac": "shift+alt+left", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineRightSelection", @@ -1613,7 +1664,7 @@ "command": "leointeg.moveOutlineRightSelectionFromOutline", "key": "shift+alt+right", "mac": "shift+alt+right", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineUpSelection", @@ -1625,7 +1676,7 @@ "command": "leointeg.moveOutlineUpSelectionFromOutline", "key": "shift+alt+up", "mac": "shift+alt+up", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.insertNodeSelection", @@ -1637,7 +1688,7 @@ "command": "leointeg.insertNodeSelectionFromOutline", "key": "ctrl+i", "mac": "cmd+i", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.insertNodeSelectionInterrupt", @@ -1659,7 +1710,7 @@ "win": "ctrl+oem_7", "linux": "ctrl+'", "mac": "cmd+[Backquote]", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.cutNodeSelection", @@ -1671,7 +1722,7 @@ "command": "leointeg.cutNodeSelectionFromOutline", "key": "ctrl+shift+x", "mac": "cmd+shift+x", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.copyNodeSelection", @@ -1683,7 +1734,7 @@ "command": "leointeg.copyNodeSelection", "key": "ctrl+shift+c", "mac": "cmd+shift+c", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.pasteNodeAtSelection", @@ -1695,7 +1746,7 @@ "command": "leointeg.pasteNodeAtSelectionFromOutline", "key": "ctrl+shift+v", "mac": "cmd+shift+v", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.deleteSelection", @@ -1707,7 +1758,7 @@ "command": "leointeg.deleteSelectionFromOutline", "key": "ctrl+shift+backspace", "mac": "cmd+shift+backspace", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration/" + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" } ], "resourceLabelFormatters": [ diff --git a/src/config.ts b/src/config.ts index e99eaca1..8a12a75f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,12 +12,14 @@ export class Config implements ConfigMembers { // TODO : Should use default values in a centralized way public checkForChangeExternalFiles: string = "none"; // Used in leoBridge script public defaultReloadIgnore: string = "none"; // Used in leoBridge script + public leoTreeBrowse: boolean = false; public treeKeepFocus: boolean = true; public treeKeepFocusWhenAside: boolean = false; public treeInExplorer: boolean = true; public showOpenAside: boolean = true; public statusBarString: string = ""; public statusBarColor: string = ""; + public showEditOnNodes: boolean = true; public showArrowsOnNodes: boolean = false; public showAddOnNodes: boolean = false; public showMarkOnNodes: boolean = false; @@ -45,12 +47,15 @@ export class Config implements ConfigMembers { return { checkForChangeExternalFiles: this.checkForChangeExternalFiles, // Used in leoBridge script defaultReloadIgnore: this.defaultReloadIgnore, // Used in leoBridge script + + leoTreeBrowse: this.leoTreeBrowse, treeKeepFocus: this.treeKeepFocus, treeKeepFocusWhenAside: this.treeKeepFocusWhenAside, treeInExplorer: this.treeInExplorer, showOpenAside: this.showOpenAside, statusBarString: this.statusBarString, statusBarColor: this.statusBarColor, + showEditOnNodes: this.showEditOnNodes, showArrowsOnNodes: this.showArrowsOnNodes, showAddOnNodes: this.showAddOnNodes, showMarkOnNodes: this.showMarkOnNodes, @@ -114,14 +119,17 @@ export class Config implements ConfigMembers { // TODO : Should use default values in a centralized way this.checkForChangeExternalFiles = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.CHECK_FOR_CHANGE_EXTERNAL_FILES, "none"); this.defaultReloadIgnore = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.DEFAULT_RELOAD_IGNORE, "none"); + this.leoTreeBrowse = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.LEO_TREE_BROWSE, true); this.treeInExplorer = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.TREE_IN_EXPLORER, true); this.showOpenAside = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.SHOW_OPEN_ASIDE, true); + this.showEditOnNodes = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.SHOW_EDIT, false); this.showArrowsOnNodes = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.SHOW_ARROWS, false); this.showAddOnNodes = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.SHOW_ADD, false); this.showMarkOnNodes = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.SHOW_MARK, false); this.showCloneOnNodes = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.SHOW_CLONE, false); this.showCopyOnNodes = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.SHOW_COPY, false); // * Interface settings + this.leoTreeBrowse = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.LEO_TREE_BROWSE, true); this.treeKeepFocus = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.TREE_KEEP_FOCUS, true); this.treeKeepFocusWhenAside = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.TREE_KEEP_FOCUS_WHEN_ASIDE, false); // * Server and connection automation @@ -132,8 +140,10 @@ export class Config implements ConfigMembers { this.connectionPort = vscode.workspace.getConfiguration(Constants.CONFIG_NAME).get(Constants.CONFIG.IP_PORT, Constants.TCPIP_DEFAULT_PORT); // 32125 // * Set context for tree items visibility that are based on config options this._leoIntegration.sendConfigToServer(this.getConfig()); + utils.setContext(Constants.CONTEXT_FLAGS.LEO_TREE_BROWSE, this.leoTreeBrowse); utils.setContext(Constants.CONTEXT_FLAGS.TREE_IN_EXPLORER, this.treeInExplorer); utils.setContext(Constants.CONTEXT_FLAGS.SHOW_OPEN_ASIDE, this.showOpenAside); + utils.setContext(Constants.CONTEXT_FLAGS.SHOW_EDIT, this.showEditOnNodes); utils.setContext(Constants.CONTEXT_FLAGS.SHOW_ARROWS, this.showArrowsOnNodes); utils.setContext(Constants.CONTEXT_FLAGS.SHOW_ADD, this.showAddOnNodes); utils.setContext(Constants.CONTEXT_FLAGS.SHOW_MARK, this.showMarkOnNodes); diff --git a/src/constants.ts b/src/constants.ts index 5e1ed96c..f95ba774 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -126,12 +126,14 @@ export class Constants { public static CONFIG = { CHECK_FOR_CHANGE_EXTERNAL_FILES: "checkForChangeExternalFiles", DEFAULT_RELOAD_IGNORE: "defaultReloadIgnore", + LEO_TREE_BROWSE: "leoTreeBrowse", TREE_KEEP_FOCUS: "treeKeepFocus", TREE_KEEP_FOCUS_WHEN_ASIDE: "treeKeepFocusWhenAside", STATUSBAR_STRING: "statusBarString", STATUSBAR_COLOR: "statusBarColor", TREE_IN_EXPLORER: "treeInExplorer", SHOW_OPEN_ASIDE: "showOpenAside", + SHOW_EDIT: "showEditOnNodes", SHOW_ARROWS: "showArrowsOnNodes", SHOW_ADD: "showAddOnNodes", SHOW_MARK: "showMarkOnNodes", @@ -171,8 +173,10 @@ export class Constants { DOCUMENT_SELECTED_UNTITLED: "leoDocumentSelectedUntitled", DOCUMENT_UNTITLED: "leoDocumentUntitled", // Flags that match specific LeoInteg config settings + LEO_TREE_BROWSE: Constants.CONFIG.LEO_TREE_BROWSE, // Leo outline also in the explorer view TREE_IN_EXPLORER: Constants.CONFIG.TREE_IN_EXPLORER, // Leo outline also in the explorer view SHOW_OPEN_ASIDE: Constants.CONFIG.SHOW_OPEN_ASIDE, // Show 'open aside' in context menu + SHOW_EDIT: Constants.CONFIG.SHOW_EDIT, // Hover Icons on outline nodes SHOW_ARROWS: Constants.CONFIG.SHOW_ARROWS, // Hover Icons on outline nodes SHOW_ADD: Constants.CONFIG.SHOW_ADD, // Hover Icons on outline nodes SHOW_MARK: Constants.CONFIG.SHOW_MARK, // Hover Icons on outline nodes @@ -309,6 +313,9 @@ export class Constants { // * Outline selection SELECT_NODE: "selectTreeNode", OPEN_ASIDE: "openAside", + // * Goto operations + + // * Leo Operations UNDO: "undo", // From command Palette UNDO_FO: "undoFromOutline", // from button, return focus on OUTLINE @@ -316,6 +323,7 @@ export class Constants { REDO_FO: "redoFromOutline", // from button, return focus on OUTLINE EXECUTE: "executeScriptSelection", // TODO : add to #34 @boltex detect focused panel for command-palette to return focus where appropriate SHOW_BODY: "showBody", + SHOW_OUTLINE: "showOutline", SHOW_LOG: "showLogPane", SORT_CHILDREN: "sortChildrenSelection", // TODO : add to #34 @boltex detect focused panel for command-palette to return focus where appropriate SORT_SIBLING: "sortSiblingsSelection", // TODO : add to #34 @boltex detect focused panel for command-palette to return focus where appropriate diff --git a/src/extension.ts b/src/extension.ts index efde4611..36ca8d1a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -40,7 +40,8 @@ export function activate(p_context: vscode.ExtensionContext) { [w_cmdPrefix + Constants.COMMANDS.START_SERVER, () => w_leoIntegration.startServer()], [w_cmdPrefix + Constants.COMMANDS.CONNECT, () => w_leoIntegration.connect()], [w_cmdPrefix + Constants.COMMANDS.SHOW_LOG, () => w_leoIntegration.showLogPane()], - [w_cmdPrefix + Constants.COMMANDS.SHOW_BODY, () => w_leoIntegration.showBody(false)], // Expose to other expansions only, (not in menus for minimal footprint) + [w_cmdPrefix + Constants.COMMANDS.SHOW_BODY, () => w_leoIntegration.showBody(false)], // Also focuses on body + [w_cmdPrefix + Constants.COMMANDS.SHOW_OUTLINE, () => w_leoIntegration.showOutline(true)], // Also focuses on outline [w_cmdPrefix + Constants.COMMANDS.NEW_FILE, () => w_leoIntegration.newLeoFile()], [w_cmdPrefix + Constants.COMMANDS.SWITCH_FILE, () => w_leoIntegration.switchLeoFile()], diff --git a/src/leoIntegration.ts b/src/leoIntegration.ts index e0286f18..a78d1cf1 100644 --- a/src/leoIntegration.ts +++ b/src/leoIntegration.ts @@ -518,7 +518,7 @@ export class LeoIntegration { * @param p_explorerView Flag to signify that the treeview who triggered this event is the one in the explorer view */ private _onTreeViewVisibilityChanged(p_event: vscode.TreeViewVisibilityChangeEvent, p_explorerView: boolean): void { - if (p_event.visible && this.lastSelectedNode) { + if (p_event.visible) { this._lastVisibleTreeView = p_explorerView ? this._leoTreeExplorerView : this._leoTreeStandaloneView; this._setTreeViewTitle(); this._needLastSelectedRefresh = true; // Its a new node in a new tree so refresh lastSelectedNode too @@ -665,6 +665,21 @@ export class LeoIntegration { }); } + /** + * * Show the outline, with Leo's selected node also selected, and optionally focussed + * @param p_focusOutline Flag for focus to be placed in outline + */ + public showOutline(p_focusOutline: boolean): void { + if (this._lastSelectedNode) { + this._lastVisibleTreeView.reveal(this._lastSelectedNode, { + select: true, + focus: p_focusOutline + }).then(() => { + // console.log('done showing/revealing outline'); + }); + } + } + /** * * Refreshes the outline. A reveal type can be passed along to specify the reveal type for the selected node * @param p_revealType Facultative reveal type to specify type of reveal when the 'selected node' is encountered @@ -673,6 +688,7 @@ export class LeoIntegration { if (p_revealType !== undefined) { // To check if selected node should self-select while redrawing whole tree this._revealType = p_revealType; // To be read/cleared (in arrayToLeoNodesArray instead of directly by nodes) } + // Force showing last used Leo outline first if (this._lastSelectedNode && !(this._leoTreeExplorerView.visible || this._leoTreeStandaloneView.visible)) { this._lastVisibleTreeView.reveal(this._lastSelectedNode).then(() => { this._leoTreeDataProvider.refreshTreeRoot(); diff --git a/src/types.d.ts b/src/types.d.ts index 578d3c49..c13a7fde 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -7,12 +7,14 @@ import { LeoNode } from "./leoNode"; export interface ConfigMembers { checkForChangeExternalFiles: string; defaultReloadIgnore: string; + leoTreeBrowse: boolean; treeKeepFocus: boolean; treeKeepFocusWhenAside: boolean; statusBarString: string; statusBarColor: string; treeInExplorer: boolean; showOpenAside: boolean; + showEditOnNodes: boolean; showArrowsOnNodes: boolean; showAddOnNodes: boolean; showMarkOnNodes: boolean; diff --git a/src/webviews/apps/index.html b/src/webviews/apps/index.html index d2da52c6..5adf5d75 100644 --- a/src/webviews/apps/index.html +++ b/src/webviews/apps/index.html @@ -55,13 +55,13 @@

LeoInteg

- Welcome to LeoInteg 0.1.12 + Welcome to LeoInteg 0.1.13

@@ -202,6 +202,17 @@

+
+
+ + +
+ Have arrow keys move selection instead of a cursor when focus is on the tree outline +
+
src="#{root}/resources/add.png" data-visibility="showAddOnNodes" /> + src="#{root}/resources/editHeadline.png" + data-visibility="showEditOnNodes" />
+
+
+ + +
+ Shows 'Edit Headline' on hover +
Date: Mon, 6 Jul 2020 03:02:38 -0400 Subject: [PATCH 2/7] Worked on new commands --- README.md | 6 ++--- leoInteg.leo | 45 +++++++++++++++++++++++++++++++++++++ leobridgeserver.py | 28 +++++++++++++++++++++++ package.json | 56 ++++++++++++++++++++++++++++++++++++++++++++++ src/constants.ts | 24 +++++++++++++++----- src/extension.ts | 9 ++++++++ 6 files changed, 160 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d75ade6b..2fa61481 100644 --- a/README.md +++ b/README.md @@ -114,10 +114,10 @@ See [Troubleshoot Linux Keybindings](https://github.com/microsoft/vscode/wiki/Ke ### Move outline keyboard commands -For some users, the **`Ctrl+D`** keybinding is already assigned. -To help with this conflict, outline-move keyboard commands will only trigger +For some users, the **`Ctrl+D`** and **`Ctrl+T`** keybinding are already assigned. +To help with this conflict, outline-move keyboard commands, and switch focus command will only trigger with the additional condition of having no text selection in the editor. -So select at least one character to use the previously assigned **`Ctrl+D`** command in body panes. +So select at least one character to use the previously assigned original keyboard commands while focus is in the body pane. > This extension is still in development, so please refer to its [issue tracker](https://github.com/boltex/leointeg/issues) to learn more about its intended features, or to contribute with additional information if you encounter other issues yourself. diff --git a/leoInteg.leo b/leoInteg.leo index cc46cf26..828ad511 100644 --- a/leoInteg.leo +++ b/leoInteg.leo @@ -68,6 +68,15 @@ outputPNode outputPNodes +Outline Goto Commands +gotoFirstVisible +gotoLastVisible +gotoLastSibling +gotoNextVisible +gotoPrevVisible +contractOrGoLeft +expandAndGoRight + Outline Editing Commands markPNode unmarkPNode @@ -1504,6 +1513,42 @@ wsPort = 32125 '''Used to override g.app.gui.ask[XXX] dialogs answers''' return "yes" + + +def gotoFirstVisible(self, p_ap): + """Select the first visible node of the selected chapter or hoist.""" + return self.outlineCommand("goToFirstVisibleNode", p_ap) + + +def gotoLastSibling(self, p_ap): + """Select the last sibling of the selected node.""" + return self.outlineCommand("goToLastSibling", p_ap) + + +def contractOrGoLeft(self, p_ap): + """Simulate the left Arrow Key in folder of Windows Explorer.""" + return self.outlineCommand("contractNodeOrGoToParent", p_ap) + + +def expandAndGoRight(self, p_ap): + """If a node has children, expand it if needed and go to the first child.""" + return self.outlineCommand("expandNodeAndGoToFirstChild", p_ap) + + +def gotoNextVisible(self, p_ap): + """Select the visible node following the presently selected node.""" + return self.outlineCommand("selectVisNext", p_ap) + + +def gotoPrevVisible(self, p_ap): + """Select the visible node preceding the presently selected node.""" + return self.outlineCommand("selectVisBack", p_ap) + + +def gotoLastVisible(self, p_ap): + """Select the last visible node of selected chapter or hoist.""" + return self.outlineCommand("goToLastVisibleNode", p_ap) + diff --git a/leobridgeserver.py b/leobridgeserver.py index b26b1517..30eef51a 100644 --- a/leobridgeserver.py +++ b/leobridgeserver.py @@ -715,6 +715,34 @@ def outputPNodes(self, p_pList): w_apList.append(self.p_to_ap(p)) return self.sendLeoBridgePackage("nodes", w_apList) # Multiple nodes, plural + def gotoFirstVisible(self, p_ap): + """Select the first visible node of the selected chapter or hoist.""" + return self.outlineCommand("goToFirstVisibleNode", p_ap) + + def gotoLastVisible(self, p_ap): + """Select the last visible node of selected chapter or hoist.""" + return self.outlineCommand("goToLastVisibleNode", p_ap) + + def gotoLastSibling(self, p_ap): + """Select the last sibling of the selected node.""" + return self.outlineCommand("goToLastSibling", p_ap) + + def gotoNextVisible(self, p_ap): + """Select the visible node following the presently selected node.""" + return self.outlineCommand("selectVisNext", p_ap) + + def gotoPrevVisible(self, p_ap): + """Select the visible node preceding the presently selected node.""" + return self.outlineCommand("selectVisBack", p_ap) + + def contractOrGoLeft(self, p_ap): + """Simulate the left Arrow Key in folder of Windows Explorer.""" + return self.outlineCommand("contractNodeOrGoToParent", p_ap) + + def expandAndGoRight(self, p_ap): + """If a node has children, expand it if needed and go to the first child.""" + return self.outlineCommand("expandNodeAndGoToFirstChild", p_ap) + def markPNode(self, p_ap): '''Mark a node, don't select it''' if p_ap: diff --git a/package.json b/package.json index 0d6b6c3e..770f7657 100644 --- a/package.json +++ b/package.json @@ -679,6 +679,46 @@ "category": "Leo", "title": "Sort Siblings" }, + { + "command": "leointeg.sortSiblingsSelectionFromOutline", + "category": "Leo", + "title": "Sort Siblings" + }, + { + "command": "leointeg.gotoFirstVisible", + "category": "Leo", + "title": "Goto First Visible" + }, + { + "command": "leointeg.gotoLastVisible", + "category": "Leo", + "title": "Goto Last Visible" + }, + { + "command": "leointeg.gotoLastSibling", + "category": "Leo", + "title": "Goto Last Sibling" + }, + { + "command": "leointeg.gotoNextVisible", + "category": "Leo", + "title": "Goto Next Visible" + }, + { + "command": "leointeg.gotoPrevVisible", + "category": "Leo", + "title": "Goto Prev Visible" + }, + { + "command": "leointeg.contractOrGoLeft", + "category": "Leo", + "title": "Contract Or Go Left" + }, + { + "command": "leointeg.expandAndGoRight", + "category": "Leo", + "title": "Expand And Go Right" + }, { "command": "leointeg.hoistNode", "category": "Leo", @@ -1121,6 +1161,10 @@ "command": "leointeg.showOutline", "when": "false" }, + { + "command": "leointeg.sortSiblingsSelectionFromOutline", + "when": "false" + }, { "command": "leointeg.refreshFromDiskSelectionFromOutline", "when": "false" @@ -1460,6 +1504,18 @@ ] }, "keybindings": [ + { + "command": "leointeg.sortSiblingsSelection", + "key": "alt+a", + "mac": "alt+a", + "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + }, + { + "command": "leointeg.sortSiblingsSelectionFromOutline", + "key": "alt+a", + "mac": "alt+a", + "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, { "command": "leointeg.showOutline", "key": "alt+t", diff --git a/src/constants.ts b/src/constants.ts index f95ba774..92c47117 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -39,7 +39,7 @@ export class Constants { /** * * Strings used as language id (default is "leobody") - * TODO : Add more languages strings for when directives such as @language are used throughout body panes + * TODO : #56 @boltex Add more languages strings for when directives such as @language are used throughout body panes */ public static BODY_LANGUAGES = { default: "leobody" @@ -241,6 +241,14 @@ export class Constants { CLOSE_FILE: "closeFile", SAVE_FILE: "saveFile", SAVE_CLOSE_FILE: "saveCloseFile", // Save and close current document + // * Goto operations + GOTO_FIRST_VISIBLE: "gotoFirstVisible", + GOTO_LAST_VISIBLE: "gotoLastVisible", + GOTO_LAST_SIBLING: "gotoLastSibling", + GOTO_NEXT_VISIBLE: "gotoNextVisible", + GOTO_PREV_VISIBLE: "gotoPrevVisible", + CONTRACT_OR_GO_LEFT: "contractOrGoLeft", + EXPAND_AND_GO_RIGHT: "expandAndGoRight", // * Leo Operations MARK_PNODE: "markPNode", UNMARK_PNODE: "unmarkPNode", @@ -313,9 +321,14 @@ export class Constants { // * Outline selection SELECT_NODE: "selectTreeNode", OPEN_ASIDE: "openAside", - // * Goto operations - - + // * Goto operations that always finish with focus in outline + GOTO_FIRST_VISIBLE: "gotoFirstVisible", + GOTO_LAST_VISIBLE: "gotoLastVisible", + GOTO_LAST_SIBLING: "gotoLastSibling", + GOTO_NEXT_VISIBLE: "gotoNextVisible", + GOTO_PREV_VISIBLE: "gotoPrevVisible", + CONTRACT_OR_GO_LEFT: "contractOrGoLeft", + EXPAND_AND_GO_RIGHT: "expandAndGoRight", // * Leo Operations UNDO: "undo", // From command Palette UNDO_FO: "undoFromOutline", // from button, return focus on OUTLINE @@ -326,7 +339,8 @@ export class Constants { SHOW_OUTLINE: "showOutline", SHOW_LOG: "showLogPane", SORT_CHILDREN: "sortChildrenSelection", // TODO : add to #34 @boltex detect focused panel for command-palette to return focus where appropriate - SORT_SIBLING: "sortSiblingsSelection", // TODO : add to #34 @boltex detect focused panel for command-palette to return focus where appropriate + SORT_SIBLING: "sortSiblingsSelection", + SORT_SIBLING_FO: "sortSiblingsSelectionFromOutline", CONTRACT_ALL: "contractAll", // From command Palette CONTRACT_ALL_FO: "contractAllFromOutline", // from button, return focus on OUTLINE // * Commands from tree panel buttons or context: focus on OUTLINE diff --git a/src/extension.ts b/src/extension.ts index 36ca8d1a..69868c2d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -119,6 +119,15 @@ export function activate(p_context: vscode.ExtensionContext) { [w_cmdPrefix + Constants.COMMANDS.SORT_CHILDREN, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.SORT_CHILDREN, undefined, RefreshType.RefreshTree, false)], [w_cmdPrefix + Constants.COMMANDS.SORT_SIBLING, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.SORT_SIBLINGS, undefined, RefreshType.RefreshTree, false)], + [w_cmdPrefix + Constants.COMMANDS.SORT_SIBLING_FO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.SORT_SIBLINGS, undefined, RefreshType.RefreshTree, true)], + + [w_cmdPrefix + Constants.COMMANDS.GOTO_FIRST_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_FIRST_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_LAST_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_LAST_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_LAST_SIBLING, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_LAST_SIBLING, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_PREV_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_PREV_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.CONTRACT_OR_GO_LEFT, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.CONTRACT_OR_GO_LEFT, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.EXPAND_AND_GO_RIGHT, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.EXPAND_AND_GO_RIGHT, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.UNDO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.UNDO, undefined, RefreshType.RefreshTreeAndBody, false)], [w_cmdPrefix + Constants.COMMANDS.UNDO_FO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.UNDO, undefined, RefreshType.RefreshTreeAndBody, true)], From 3d824d74b2e1f7791e26843c52f4998e9165ff2e Mon Sep 17 00:00:00 2001 From: felix Date: Mon, 6 Jul 2020 03:13:52 -0400 Subject: [PATCH 3/7] Worked on some new 'GOTO' commands. Todo: Needs keybindings and context 'when' clauses in package.json --- leoInteg.leo | 6 ++++++ leobridgeserver.py | 4 ++++ src/constants.ts | 4 ++-- src/extension.ts | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/leoInteg.leo b/leoInteg.leo index 828ad511..e5fb7eaf 100644 --- a/leoInteg.leo +++ b/leoInteg.leo @@ -74,6 +74,7 @@ gotoLastSibling gotoNextVisible gotoPrevVisible +gotoNextMarked contractOrGoLeft expandAndGoRight @@ -1549,6 +1550,11 @@ wsPort = 32125 """Select the last visible node of selected chapter or hoist.""" return self.outlineCommand("goToLastVisibleNode", p_ap) + +def gotoNextMarked(self, p_ap): + """Select the next marked node.""" + return self.outlineCommand("goToNextMarkedHeadline", p_ap) + diff --git a/leobridgeserver.py b/leobridgeserver.py index 30eef51a..1b3fff75 100644 --- a/leobridgeserver.py +++ b/leobridgeserver.py @@ -735,6 +735,10 @@ def gotoPrevVisible(self, p_ap): """Select the visible node preceding the presently selected node.""" return self.outlineCommand("selectVisBack", p_ap) + def gotoNextMarked(self, p_ap): + """Select the next marked node.""" + return self.outlineCommand("goToNextMarkedHeadline", p_ap) + def contractOrGoLeft(self, p_ap): """Simulate the left Arrow Key in folder of Windows Explorer.""" return self.outlineCommand("contractNodeOrGoToParent", p_ap) diff --git a/src/constants.ts b/src/constants.ts index 92c47117..b05d4df9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -247,6 +247,7 @@ export class Constants { GOTO_LAST_SIBLING: "gotoLastSibling", GOTO_NEXT_VISIBLE: "gotoNextVisible", GOTO_PREV_VISIBLE: "gotoPrevVisible", + GOTO_NEXT_MARKED: "gotoNextMarked", // #23 @boltex CONTRACT_OR_GO_LEFT: "contractOrGoLeft", EXPAND_AND_GO_RIGHT: "expandAndGoRight", // * Leo Operations @@ -284,7 +285,6 @@ export class Constants { EXTRACT_NAMES: "extractNames", // #15 @boltex COPY_MARKED: "copyMarked", // #23 @boltex DIFF_MARKED_NODES: "diffMarkedNodes", // #23 @boltex - GOTO_NEXT_MARKED: "gotoNextMarked", // #23 @boltex MARK_CHANGED_ITEMS: "markChangedItems", // #23 @boltex MARK_SUBHEADS: "markSubheads", // #23 @boltex UNMARK_ALL: "unmarkAll", // #23 @boltex @@ -327,6 +327,7 @@ export class Constants { GOTO_LAST_SIBLING: "gotoLastSibling", GOTO_NEXT_VISIBLE: "gotoNextVisible", GOTO_PREV_VISIBLE: "gotoPrevVisible", + GOTO_NEXT_MARKED: "gotoNextMarked", CONTRACT_OR_GO_LEFT: "contractOrGoLeft", EXPAND_AND_GO_RIGHT: "expandAndGoRight", // * Leo Operations @@ -410,7 +411,6 @@ export class Constants { EXTRACT_NAMES: "extractNames", COPY_MARKED: "copyMarked", DIFF_MARKED_NODES: "diffMarkedNodes", - GOTO_NEXT_MARKED: "gotoNextMarked", MARK_CHANGED_ITEMS: "markChangedItems", MARK_SUBHEADS: "markSubheads", UNMARK_ALL: "unmarkAll", diff --git a/src/extension.ts b/src/extension.ts index 69868c2d..2c81b7fe 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -126,6 +126,7 @@ export function activate(p_context: vscode.ExtensionContext) { [w_cmdPrefix + Constants.COMMANDS.GOTO_LAST_SIBLING, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_LAST_SIBLING, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_PREV_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_PREV_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_MARKED, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_MARKED, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.CONTRACT_OR_GO_LEFT, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.CONTRACT_OR_GO_LEFT, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.EXPAND_AND_GO_RIGHT, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.EXPAND_AND_GO_RIGHT, undefined, RefreshType.RefreshTreeAndBody, true)], @@ -147,7 +148,6 @@ export function activate(p_context: vscode.ExtensionContext) { [w_cmdPrefix + Constants.COMMANDS.EXTRACT_NAMES, () => vscode.window.showInformationMessage("TODO: extractNames command")], [w_cmdPrefix + Constants.COMMANDS.COPY_MARKED, () => vscode.window.showInformationMessage("TODO: copyMarked command")], [w_cmdPrefix + Constants.COMMANDS.DIFF_MARKED_NODES, () => vscode.window.showInformationMessage("TODO: diffMarkedNodes command")], - [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_MARKED, () => vscode.window.showInformationMessage("TODO: gotoNextMarked command")], [w_cmdPrefix + Constants.COMMANDS.MARK_CHANGED_ITEMS, () => vscode.window.showInformationMessage("TODO: markChangedItems command")], [w_cmdPrefix + Constants.COMMANDS.MARK_SUBHEADS, () => vscode.window.showInformationMessage("TODO: markSubheads command")], [w_cmdPrefix + Constants.COMMANDS.UNMARK_ALL, () => vscode.window.showInformationMessage("TODO: unmarkAll command")], From dc6d071b0f606fb0bbf1b3e9c36a7183478444a4 Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 7 Jul 2020 02:55:26 -0400 Subject: [PATCH 4/7] Added more commands Added direct tree navigation, new config option. --- CHANGELOG.md | 4 +- CONTRIBUTING.md | 2 + README.md | 25 +++- leoInteg.leo | 18 ++- leobridgeserver.py | 12 +- package-lock.json | 2 +- package.json | 243 +++++++++++++++++++++++++++++------- resources/dark/dehoist.svg | 6 + resources/light/dehoist.svg | 6 + src/constants.ts | 15 ++- src/extension.ts | 14 ++- 11 files changed, 285 insertions(+), 62 deletions(-) create mode 100644 resources/dark/dehoist.svg create mode 100644 resources/light/dehoist.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bb08da5..0f1e22aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ ## 0.1.13 - Added support for precise focus placement, focus switch between tree/body. -- Added commands and keybindings for 'goto' operations and other commands. +- Made the 'edit headline' hover icon removable, in order to enable 'Tab' keybinding to go from tree to body directly. +- Added commands and keybindings for 'goto' operations 'hoist/dehoist' [#25](https://github.com/boltex/leointeg/issues/25) and other commands. [#30](https://github.com/boltex/leointeg/issues/30) +- Added support for Leo-Style outline navigation. [#43](https://github.com/boltex/leointeg/issues/43) Has to be enabled with an option in the config settings: "Use Leo Tree Browsing" which makes arrow keys move selection instead of a cursor when focus is on the tree outline. ## 0.1.12 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea4de99f..edf4faf2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,8 @@ If you're having problems with the procedures below, try [running this sample ex ## Development requirements +- **use Leo's 'devel' branch** (This is temporary until Leo's next release) + - Make sure you have [Node.js](https://nodejs.org/en/download/) and [Git](https://git-scm.com/downloads) installed. - Check your node.js version by typing `node -v` in a terminal. [The latest lts version is 12.18.0](https://nodejs.org/en/download/). diff --git a/README.md b/README.md index 2fa61481..d7251c16 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ or on [github](https://github.com/leo-editor/leo-editor), and vscode at [code.vi ## Development version installation -In addition to the above requirements, make sure you have Node.js and Git installed, then clone the sources and run `npm install` in a terminal to install the remaining development dependencies. +In addition to the above requirements, **use Leo's 'devel' branch** (This is temporary until Leo's next release), make sure you have Node.js and Git installed, then clone the sources and run `npm install` in a terminal to install the remaining development dependencies. ![run extension](/resources/run-extension.png) @@ -32,6 +32,7 @@ You can then run the **Run Extension** target, as shown above, in the **Debug Vi ## Features - UI controls such as a **Leo Outline** in the explorer view, or as a standalone sidebar, **body panes**, **opened documents selector** and **Log Window**. +- Keybindings that match those from Leo, and a **'Leo Tree Browsing'** switch that enables Leo-style arrow keys behavior, for outline keyboard navigation. - A **welcome screen** that also gives access to this extension's **settings**. - **Derived files change detection**. See [External Files](#derive-external-files) below for more details - Access **Leo commands** with context menus, outline-node hover icons, keyboard shortcuts, or the command palette: @@ -46,7 +47,7 @@ You can then run the **Run Extension** target, as shown above, in the **Debug Vi > _More commands are available by opening the **Command Palette** and typing 'Leo'_ -| Keybinding | | | Command | +| Commands Keybinding | | | Command | | :------------------------- | :-- | :-------------------- | :----------------- | | `Alt + -` | | | Contract All | | `Ctrl + I` | | | Insert Node | @@ -59,11 +60,23 @@ You can then run the **Run Extension** target, as shown above, in the **Debug Vi | `Ctrl + B` | | | Execute Script | | `Ctrl + M` | | | Mark / Unmark | | `Ctrl + {` | | `Ctrl + }` | Promote / Demote | +| `Alt + A` | | | Sort Siblings | | `Ctrl + U` | or | `Shift + Alt + Up` | Move Outline Up | | `Ctrl + D` | or | `Shift + Alt + Down` | Move Outline Down | | `Ctrl + L` | or | `Shift + Alt + Left` | Move Outline Left | | `Ctrl + R` | or | `Shift + Alt + Right` | Move Outline Right | +### Tree Browsing Keybindings + +| Tree Browsing Keybinding | | With **'Leo Tree Browsing'** enabled | Command | +| :----------------------- | :-- | :----------------------------------- | :----------------------- | +| `Alt + Home` | | | Go To First Visible Node | +| `Alt + End` | | | Go To Last Sibling | +| `Alt + N` | | | Go To Next Clone | +| `Alt + Arrow Keys` | or | `Arrow Keys` | Browse Tree | +| `Ctrl + T` | | | Switch Tree/Body Focus | +| `Tab` | | | Focus from Tree to Body | + ## Derive External Files Use the **Save Leo File** command to derive external files. @@ -110,12 +123,13 @@ Main issues are listed below. See the repository's [Issues Page](https://github. If you're experiencing trouble with the keyboard shortcuts for the 'Clone Node' or the 'Promote' and 'Demote' commands, use **"keyboard.dispatch": "keyCode"** in your settings and restart vscode. -See [Troubleshoot Linux Keybindings](https://github.com/microsoft/vscode/wiki/Keybinding-Issues#troubleshoot-linux-keybindings) for more information. +See [Troubleshoot Linux Keybindings](https://github.com/microsoft/vscode/wiki/Keybinding-Issues#troubleshoot-linux-keybindings) +for more information. ### Move outline keyboard commands -For some users, the **`Ctrl+D`** and **`Ctrl+T`** keybinding are already assigned. -To help with this conflict, outline-move keyboard commands, and switch focus command will only trigger +For some users, the **`Alt+[Arrow Keys]`**, **`Ctrl+D`** and **`Ctrl+T`** keybinding are already assigned. +To help with this conflict, tree-browsing, outline-move keyboard commands, and switch focus command will only trigger with the additional condition of having no text selection in the editor. So select at least one character to use the previously assigned original keyboard commands while focus is in the body pane. @@ -134,6 +148,7 @@ The outline pane is made by implementing a [TreeDataProvider for vscode's TreeVi - [Edward K. Ream](https://github.com/edreamleo) creator of the [Leo Editor](https://leoeditor.com/) - [Eric Amodio](https://github.com/eamodio) for the [welcome screen templates](https://github.com/eamodio/vscode-gitlens/tree/master/src/webviews) - [Vitalije](https://github.com/vitalije) for his contributions and support +- [Arjan](https://github.com/ar-jan) for his suggestions and ideas --- diff --git a/leoInteg.leo b/leoInteg.leo index e5fb7eaf..e8ed89e8 100644 --- a/leoInteg.leo +++ b/leoInteg.leo @@ -75,6 +75,7 @@ gotoNextVisible gotoPrevVisible gotoNextMarked +gotoNextClone contractOrGoLeft expandAndGoRight @@ -244,7 +245,14 @@ To contribute, see the official issues page for current list of 'TODO's at https else: return self.outputPNodes([]) # default empty array else: - return self.outputPNodes(self.yieldAllRootChildren()) # this outputs all Root Children + if self.commander.hoistStack: + w_p = self.commander.hoistStack[-1].p + if w_p: + return self.outputPNodes([w_p]) + else: + return self.outputPNodes([]) # default empty array + else: + return self.outputPNodes(self.yieldAllRootChildren()) # this outputs all Root Children def getParent(self, p_ap): @@ -1555,6 +1563,14 @@ wsPort = 32125 """Select the next marked node.""" return self.outlineCommand("goToNextMarkedHeadline", p_ap) + +def gotoNextClone(self, p_ap): + """ + Select the next node that is a clone of the selected node. + If the selected node is not a clone, do find-next-clone. + """ + return self.outlineCommand("goToNextClone", p_ap) + diff --git a/leobridgeserver.py b/leobridgeserver.py index 1b3fff75..71e655e3 100644 --- a/leobridgeserver.py +++ b/leobridgeserver.py @@ -739,6 +739,13 @@ def gotoNextMarked(self, p_ap): """Select the next marked node.""" return self.outlineCommand("goToNextMarkedHeadline", p_ap) + def gotoNextClone(self, p_ap): + """ + Select the next node that is a clone of the selected node. + If the selected node is not a clone, do find-next-clone. + """ + return self.outlineCommand("goToNextClone", p_ap) + def contractOrGoLeft(self, p_ap): """Simulate the left Arrow Key in folder of Windows Explorer.""" return self.outlineCommand("contractNodeOrGoToParent", p_ap) @@ -990,7 +997,10 @@ def getChildren(self, p_ap): else: return self.outputPNodes([]) # default empty array else: - return self.outputPNodes(self.yieldAllRootChildren()) # this outputs all Root Children + if self.commander.hoistStack: + return self.outputPNodes([self.commander.hoistStack[-1].p]) + else: + return self.outputPNodes(self.yieldAllRootChildren()) # this outputs all Root Children def getParent(self, p_ap): '''EMIT OUT the parent of a node, as an array, even if unique or empty''' diff --git a/package-lock.json b/package-lock.json index 14280dfb..c37e9795 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "leointeg", - "version": "0.1.12", + "version": "0.1.13", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 770f7657..b85158a3 100644 --- a/package.json +++ b/package.json @@ -729,10 +729,28 @@ "category": "Leo", "title": "Hoist" }, + { + "command": "leointeg.hoistSelectionFromOutline", + "category": "Leo", + "title": "Hoist" + }, { "command": "leointeg.deHoist", "category": "Leo", - "title": "De-Hoist" + "title": "De-Hoist", + "icon": { + "light": "resources/light/dehoist.svg", + "dark": "resources/dark/dehoist.svg" + } + }, + { + "command": "leointeg.deHoistFromOutline", + "category": "Leo", + "title": "De-Hoist", + "icon": { + "light": "resources/light/dehoist.svg", + "dark": "resources/dark/dehoist.svg" + } }, { "command": "leointeg.undo", @@ -820,6 +838,16 @@ "category": "Leo", "title": "Goto Next Marked" }, + { + "command": "leointeg.gotoNextClone", + "category": "Leo", + "title": "Goto Next Clone" + }, + { + "command": "leointeg.gotoNextCloneFromOutline", + "category": "Leo", + "title": "Goto Next Clone" + }, { "command": "leointeg.markChangedItems", "category": "Leo", @@ -1079,7 +1107,7 @@ }, { "command": "leointeg.deHoist", - "when": "leoTreeOpened" + "when": "leoTreeOpened && leoCanDehoist" }, { "command": "leointeg.cloneFindAll", @@ -1117,6 +1145,10 @@ "command": "leointeg.gotoNextMarked", "when": "leoTreeOpened" }, + { + "command": "leointeg.gotoNextClone", + "when": "leoTreeOpened" + }, { "command": "leointeg.markChangedItems", "when": "leoTreeOpened" @@ -1313,9 +1345,49 @@ "command": "leointeg.demoteSelectionFromOutline", "when": "false" }, + { + "command": "leointeg.gotoNextCloneFromOutline", + "when": "false" + }, { "command": "leointeg.hoistNode", "when": "false" + }, + { + "command": "leointeg.hoistSelectionFromOutline", + "when": "false" + }, + { + "command": "leointeg.deHoistFromOutline", + "when": "false" + }, + { + "command": "leointeg.gotoFirstVisible", + "when": "false" + }, + { + "command": "leointeg.gotoLastVisible", + "when": "false" + }, + { + "command": "leointeg.gotoLastSibling", + "when": "false" + }, + { + "command": "leointeg.gotoNextVisible", + "when": "false" + }, + { + "command": "leointeg.gotoPrevVisible", + "when": "false" + }, + { + "command": "leointeg.contractOrGoLeft", + "when": "false" + }, + { + "command": "leointeg.expandAndGoRight", + "when": "false" } ], "view/title": [ @@ -1364,10 +1436,15 @@ "when": "view =~ /leoIntegration/ && leoTreeOpened && leoCanRedo", "group": "navigation@4" }, + { + "command": "leointeg.deHoistFromOutline", + "when": "view =~ /leoIntegration/ && leoTreeOpened && leoCanDehoist", + "group": "navigation@5" + }, { "command": "leointeg.contractAllFromOutline", "when": "view =~ /leoIntegration/ && leoTreeOpened", - "group": "navigation@5" + "group": "navigation@6" } ], "view/item/context": [ @@ -1441,6 +1518,11 @@ "when": "showOpenAside && viewItem =~ /leoNode/", "group": "leoNodeContext1@1" }, + { + "command": "leointeg.hoistNode", + "when": "viewItem =~ /leoNode/", + "group": "leoNodeContext1@1" + }, { "command": "leointeg.refreshFromDisk", "when": "viewItem =~ /leoNodeAtFile/", @@ -1504,107 +1586,180 @@ ] }, "keybindings": [ + { + "command": "leointeg.gotoFirstVisible", + "key": "alt+home", + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.gotoLastSibling", + "key": "alt+end", + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.gotoNextCloneFromOutline", + "key": "alt+n", + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.gotoNextClone", + "key": "alt+n", + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" + }, + { + "command": "leointeg.gotoNextVisible", + "key": "down", + "when": "leoTreeBrowse && leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.gotoNextVisible", + "key": "alt+down", + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.gotoNextVisible", + "key": "alt+down", + "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + }, + { + "command": "leointeg.gotoPrevVisible", + "key": "up", + "when": "leoTreeBrowse && leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.gotoPrevVisible", + "key": "alt+up", + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.gotoPrevVisible", + "key": "alt+up", + "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + }, + { + "command": "leointeg.contractOrGoLeft", + "key": "left", + "when": "leoTreeBrowse && leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.contractOrGoLeft", + "key": "alt+left", + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.contractOrGoLeft", + "key": "alt+left", + "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + }, + { + "command": "leointeg.expandAndGoRight", + "key": "right", + "when": "leoTreeBrowse && leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.expandAndGoRight", + "key": "alt+right", + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + }, + { + "command": "leointeg.expandAndGoRight", + "key": "alt+right", + "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + }, { "command": "leointeg.sortSiblingsSelection", "key": "alt+a", - "mac": "alt+a", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.sortSiblingsSelectionFromOutline", "key": "alt+a", - "mac": "alt+a", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.showOutline", "key": "alt+t", - "mac": "alt+t", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.showOutline", "key": "ctrl+t", - "mac": "ctrl+t", + "mac": "cmd+t", "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.showBody", "key": "ctrl+t", - "mac": "ctrl+t", + "mac": "cmd+t", "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.showBody", "key": "alt+d", - "mac": "alt+d", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.showBody", "key": "tab", - "mac": "tab", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.executeScriptSelection", "key": "ctrl+b", - "mac": "ctrl+b", + "mac": "cmd+b", "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.executeScriptSelection", "key": "ctrl+b", - "mac": "ctrl+b", + "mac": "cmd+b", "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.contractAll", "key": "alt+-", - "mac": "alt+-", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.contractAllFromOutline", "key": "alt+-", - "mac": "alt+-", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.editSelectedHeadline", "key": "ctrl+h", "mac": "cmd+h", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.editSelectedHeadlineFromOutline", "key": "ctrl+h", "mac": "cmd+h", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.markSelection", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && !leoNodeMarked && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && !leoNodeMarked && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.markSelectionFromOutline", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && !leoNodeMarked && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && !leoNodeMarked && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.unmarkSelection", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && leoNodeMarked && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && leoNodeMarked && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.unmarkSelectionFromOutline", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && leoNodeMarked && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && leoNodeMarked && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.promoteSelection", @@ -1612,7 +1767,7 @@ "win": "ctrl+oem_4", "linux": "ctrl+[", "mac": "cmd+[BracketLeft]", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.promoteSelectionFromOutline", @@ -1620,7 +1775,7 @@ "win": "ctrl+oem_4", "linux": "ctrl+[", "mac": "cmd+[BracketLeft]", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.demoteSelection", @@ -1628,7 +1783,7 @@ "win": "ctrl+oem_6", "linux": "ctrl+]", "mac": "cmd+[BracketRight]", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.demoteSelectionFromOutline", @@ -1636,7 +1791,7 @@ "win": "ctrl+oem_6", "linux": "ctrl+]", "mac": "cmd+[BracketRight]", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineDownSelection", @@ -1738,19 +1893,19 @@ "command": "leointeg.insertNodeSelection", "key": "ctrl+i", "mac": "cmd+i", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.insertNodeSelectionFromOutline", "key": "ctrl+i", "mac": "cmd+i", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.insertNodeSelectionInterrupt", "key": "ctrl+i", "mac": "cmd+i", - "when": "leoTreeOpened && !editorHasSelection && !sideBarFocus && !editorTextFocus" + "when": "leoTreeOpened && !sideBarFocus && !editorTextFocus" }, { "command": "leointeg.cloneNodeSelection", @@ -1758,7 +1913,7 @@ "win": "ctrl+oem_7", "linux": "ctrl+'", "mac": "cmd+[Backquote]", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.cloneNodeSelectionFromOutline", @@ -1766,55 +1921,55 @@ "win": "ctrl+oem_7", "linux": "ctrl+'", "mac": "cmd+[Backquote]", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.cutNodeSelection", "key": "ctrl+shift+x", "mac": "cmd+shift+x", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.cutNodeSelectionFromOutline", "key": "ctrl+shift+x", "mac": "cmd+shift+x", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.copyNodeSelection", "key": "ctrl+shift+c", "mac": "cmd+shift+c", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.copyNodeSelection", "key": "ctrl+shift+c", "mac": "cmd+shift+c", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.pasteNodeAtSelection", "key": "ctrl+shift+v", "mac": "cmd+shift+v", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.pasteNodeAtSelectionFromOutline", "key": "ctrl+shift+v", "mac": "cmd+shift+v", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.deleteSelection", "key": "ctrl+shift+backspace", "mac": "cmd+shift+backspace", - "when": "leoTreeOpened && !editorHasSelection && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.deleteSelectionFromOutline", "key": "ctrl+shift+backspace", "mac": "cmd+shift+backspace", - "when": "leoTreeOpened && !editorHasSelection && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" } ], "resourceLabelFormatters": [ diff --git a/resources/dark/dehoist.svg b/resources/dark/dehoist.svg new file mode 100644 index 00000000..1fe76a85 --- /dev/null +++ b/resources/dark/dehoist.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/light/dehoist.svg b/resources/light/dehoist.svg new file mode 100644 index 00000000..ea89fb3f --- /dev/null +++ b/resources/light/dehoist.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/constants.ts b/src/constants.ts index b05d4df9..0cdb15af 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -247,7 +247,8 @@ export class Constants { GOTO_LAST_SIBLING: "gotoLastSibling", GOTO_NEXT_VISIBLE: "gotoNextVisible", GOTO_PREV_VISIBLE: "gotoPrevVisible", - GOTO_NEXT_MARKED: "gotoNextMarked", // #23 @boltex + GOTO_NEXT_MARKED: "gotoNextMarked", + GOTO_NEXT_CLONE: "gotoNextClone", CONTRACT_OR_GO_LEFT: "contractOrGoLeft", EXPAND_AND_GO_RIGHT: "expandAndGoRight", // * Leo Operations @@ -273,10 +274,10 @@ export class Constants { UNDO: "undo", REDO: "redo", EXECUTE_SCRIPT: "executeScript", - GET_STATES: "getStates", // #18 @boltex - // TODO : More commands to implement #15, #23, #24, #25 @boltex - HOIST_PNODE: "hoistPNode", // #25 @boltex - DEHOIST: "deHoist", // #25 @boltex + GET_STATES: "getStates", + HOIST_PNODE: "hoistPNode", + DEHOIST: "deHoist", + // TODO : @boltex More commands to implement #15, #23, #24 CLONE_FIND_ALL: "cloneFindAll", // #24 @boltex CLONE_FIND_ALL_FLATTENED: "cloneFindAllFlattened", // #24 @boltex CLONE_FIND_MARKED: "cloneFindMarked", // #24 @boltex @@ -328,6 +329,8 @@ export class Constants { GOTO_NEXT_VISIBLE: "gotoNextVisible", GOTO_PREV_VISIBLE: "gotoPrevVisible", GOTO_NEXT_MARKED: "gotoNextMarked", + GOTO_NEXT_CLONE: "gotoNextClone", + GOTO_NEXT_CLONE_FO: "gotoNextCloneFromOutline", CONTRACT_OR_GO_LEFT: "contractOrGoLeft", EXPAND_AND_GO_RIGHT: "expandAndGoRight", // * Leo Operations @@ -402,7 +405,9 @@ export class Constants { // * - - - - - - - - - - - - - - - not implemented yet HOIST: "hoistNode", HOIST_SELECTION: "hoistSelection", + HOIST_SELECTION_FO: "hoistSelectionFromOutline", DEHOIST: "deHoist", + DEHOIST_FO: "deHoistFromOutline", CLONE_FIND_ALL: "cloneFindAll", CLONE_FIND_ALL_FLATTENED: "cloneFindAllFlattened", CLONE_FIND_MARKED: "cloneFindMarked", diff --git a/src/extension.ts b/src/extension.ts index 2c81b7fe..75e30de4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -124,6 +124,9 @@ export function activate(p_context: vscode.ExtensionContext) { [w_cmdPrefix + Constants.COMMANDS.GOTO_FIRST_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_FIRST_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_LAST_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_LAST_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_LAST_SIBLING, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_LAST_SIBLING, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_CLONE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_CLONE, undefined, RefreshType.RefreshTreeAndBody, false)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_CLONE_FO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_CLONE, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_PREV_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_PREV_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_MARKED, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_MARKED, undefined, RefreshType.RefreshTreeAndBody, true)], @@ -136,10 +139,13 @@ export function activate(p_context: vscode.ExtensionContext) { [w_cmdPrefix + Constants.COMMANDS.REDO_FO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.REDO, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.EXECUTE, () => w_leoIntegration.executeScript()], - // TODO : More commands to implement #15, #23, #24, #25 @boltex - [w_cmdPrefix + Constants.COMMANDS.HOIST, () => vscode.window.showInformationMessage("TODO: hoistNode command")], - [w_cmdPrefix + Constants.COMMANDS.HOIST_SELECTION, () => vscode.window.showInformationMessage("TODO: hoistSelection command")], - [w_cmdPrefix + Constants.COMMANDS.DEHOIST, () => vscode.window.showInformationMessage("TODO: deHoist command")], + [w_cmdPrefix + Constants.COMMANDS.HOIST, (p_node: LeoNode) => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.HOIST_PNODE, p_node, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.HOIST_SELECTION, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.HOIST_PNODE, undefined, RefreshType.RefreshTreeAndBody, false)], + [w_cmdPrefix + Constants.COMMANDS.HOIST_SELECTION_FO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.HOIST_PNODE, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.DEHOIST, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.DEHOIST, undefined, RefreshType.RefreshTreeAndBody, false)], + [w_cmdPrefix + Constants.COMMANDS.DEHOIST_FO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.DEHOIST, undefined, RefreshType.RefreshTreeAndBody, true)], + + // TODO : @boltex More commands to implement #15, #23, #24 [w_cmdPrefix + Constants.COMMANDS.CLONE_FIND_ALL, () => vscode.window.showInformationMessage("TODO: cloneFindAll command")], [w_cmdPrefix + Constants.COMMANDS.CLONE_FIND_ALL_FLATTENED, () => vscode.window.showInformationMessage("TODO: cloneFindAllFlattened command")], [w_cmdPrefix + Constants.COMMANDS.CLONE_FIND_MARKED, () => vscode.window.showInformationMessage("TODO: cloneFindMarked command")], From d82768a497fb8362e361b5fd8be91df8c21921e0 Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 7 Jul 2020 18:27:33 -0400 Subject: [PATCH 5/7] Added refresh after config changes when applicable Also added 'Please wait for SAVING CONFIG' indicator Fixes #16 --- package.json | 9 +++-- src/config.ts | 14 ++++++-- src/constants.ts | 3 +- src/leoIntegration.ts | 16 +++++++++ src/webviews/apps/index.html | 1 + src/webviews/apps/index.ts | 8 +++++ src/webviews/apps/scss/popup.scss | 55 ++++++++++++++++++++++++++++++- 7 files changed, 100 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index b85158a3..bea54058 100644 --- a/package.json +++ b/package.json @@ -1401,6 +1401,11 @@ "when": "view =~ /leoDocuments/ && leoBridgeReady", "group": "navigation@1" }, + { + "command": "leointeg.showSettingsPage", + "when": "view =~ /leoIntegration/ && !leoTreeOpened", + "group": "navigation@1" + }, { "command": "leointeg.connectToServer", "when": "view =~ /leoIntegration/ && !leoBridgeReady && !leoTreeOpened", @@ -1521,12 +1526,12 @@ { "command": "leointeg.hoistNode", "when": "viewItem =~ /leoNode/", - "group": "leoNodeContext1@1" + "group": "leoNodeContext1@2" }, { "command": "leointeg.refreshFromDisk", "when": "viewItem =~ /leoNodeAtFile/", - "group": "leoNodeContext1@1" + "group": "leoNodeContext1@3" }, { "command": "leointeg.mark", diff --git a/src/config.ts b/src/config.ts index 8a12a75f..a6e32767 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; import * as utils from "./utils"; -import { ConfigMembers } from "./types"; +import { ConfigMembers, RefreshType } from "./types"; import { Constants } from "./constants"; import { LeoIntegration } from "./leoIntegration"; @@ -33,6 +33,7 @@ export class Config implements ConfigMembers { public connectionPort: number = Constants.TCPIP_DEFAULT_PORT; private _isSettingConfig: boolean = false; + private _needsTreeRefresh: boolean = false; constructor( private _context: vscode.ExtensionContext, @@ -79,8 +80,11 @@ export class Config implements ConfigMembers { this._isSettingConfig = true; const w_promises: Thenable[] = []; const w_vscodeConfig = vscode.workspace.getConfiguration(Constants.CONFIG_NAME); - p_changes.forEach(i_change => { + if (i_change && i_change.code.includes(Constants.CONFIG_REFRESH_MATCH)) { + // Check if tree refresh is required for hover-icons to be displayed or hidden accordingly + this._needsTreeRefresh = true; + } if (w_vscodeConfig.inspect(i_change.code)!.defaultValue === i_change.value) { // set as undefined - same as default w_promises.push(w_vscodeConfig.update(i_change.code, undefined, true)); @@ -92,6 +96,12 @@ export class Config implements ConfigMembers { } }); return Promise.all(w_promises).then(() => { + if (this._needsTreeRefresh) { + this._needsTreeRefresh = false; + setTimeout(() => { + this._leoIntegration.configTreeRefresh(); + }, 200); + } this._isSettingConfig = false; this.buildFromSavedSettings(); }); diff --git a/src/constants.ts b/src/constants.ts index 0cdb15af..9507a66a 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -7,7 +7,8 @@ export class Constants { public static PUBLISHER: string = "boltex"; public static NAME: string = "leointeg"; - public static CONFIG_NAME = "leoIntegration"; + public static CONFIG_NAME: string = "leoIntegration"; + public static CONFIG_REFRESH_MATCH: string = "OnNodes"; public static TREEVIEW_ID: string = Constants.CONFIG_NAME; public static TREEVIEW_EXPLORER_ID: string = Constants.CONFIG_NAME + "Explorer"; diff --git a/src/leoIntegration.ts b/src/leoIntegration.ts index a78d1cf1..ceafda96 100644 --- a/src/leoIntegration.ts +++ b/src/leoIntegration.ts @@ -145,6 +145,7 @@ export class LeoIntegration { // * Outline Pane redraw/refresh flags. Also set when calling refreshTreeRoot // If there's no reveal and its the selected node, the old id will be re-used for the node. (see _id property in LeoNode) private _revealType: RevealType = RevealType.NoReveal; // to be read/cleared in arrayToLeoNodesArray, to check if any should self-select + private _preventShowBody = false; // Used when refreshing treeview from config: It requires not to open the body pane when refreshing. // * Documents Pane private _leoDocumentsProvider: LeoDocumentsProvider; @@ -680,6 +681,17 @@ export class LeoIntegration { } } + /** + * * Refresh tree for node hover icons refresh only + */ + public configTreeRefresh(): void { + if (this.fileOpenedReady && this.lastSelectedNode) { + this._revealType = RevealType.RevealSelect; + this._preventShowBody = true; + this._leoTreeDataProvider.refreshTreeRoot(); + } + } + /** * * Refreshes the outline. A reveal type can be passed along to specify the reveal type for the selected node * @param p_revealType Facultative reveal type to specify type of reveal when the 'selected node' is encountered @@ -903,6 +915,10 @@ export class LeoIntegration { * @param p_force_open Forces opening the body pane editor */ private _showBodyIfRequired(p_aside: boolean, p_showBodyKeepFocus: boolean, p_force_open?: boolean): Thenable { + if (this._preventShowBody) { + this._preventShowBody = false; + return Promise.resolve(vscode.window.activeTextEditor!); + } if (true || p_force_open || this._leoTreeStandaloneView.visible) { return this.showBody(p_aside, p_showBodyKeepFocus); // ! Always true for now to stabilize refreshes after derived files refreshes and others. } else { diff --git a/src/webviews/apps/index.html b/src/webviews/apps/index.html index 5adf5d75..367d561b 100644 --- a/src/webviews/apps/index.html +++ b/src/webviews/apps/index.html @@ -540,6 +540,7 @@

About Leo

+
Modified
Settings Saved
#{endOfBody} diff --git a/src/webviews/apps/index.ts b/src/webviews/apps/index.ts index 560890b9..5979b3e9 100644 --- a/src/webviews/apps/index.ts +++ b/src/webviews/apps/index.ts @@ -14,6 +14,7 @@ declare function acquireVsCodeApi(): VsCodeApi; initializeAndWatchThemeColors(); const toast = document.getElementById("saved-config-toast"); + const dirty = document.getElementById("dirty-config-toast"); // * TEST const oldState = vscode.getState(); @@ -49,6 +50,7 @@ declare function acquireVsCodeApi(): VsCodeApi; setControls(); break; case "vscodeConfig": + dirty!.className = dirty!.className.replace("show", ""); toast!.className = "show"; setTimeout(function () { toast!.className = toast!.className.replace("show", ""); }, 1500); vscodeConfig = message.config; // next changes will be confronted to those settings @@ -104,6 +106,9 @@ declare function acquireVsCodeApi(): VsCodeApi; function onInputChecked(element: HTMLInputElement) { frontConfig[element.id] = element.checked; setVisibility(frontConfig); + dirty!.className = "show"; + console.log('checked'); + applyChanges(); } function onInputBlurred(element: HTMLInputElement) { @@ -122,6 +127,9 @@ declare function acquireVsCodeApi(): VsCodeApi; } else if (element.type === 'text' && element.value.length <= element.maxLength) { frontConfig[element.id] = element.value; } + console.log('changed'); + + dirty!.className = "show"; applyChanges(); } diff --git a/src/webviews/apps/scss/popup.scss b/src/webviews/apps/scss/popup.scss index f60b27ca..ccd3d070 100644 --- a/src/webviews/apps/scss/popup.scss +++ b/src/webviews/apps/scss/popup.scss @@ -55,11 +55,64 @@ } } +#dirty-config-toast { + box-shadow: 0px 0px 28px 0 rgba(0, 0, 0, 0.5); + // background-color: #000 !important; + + cursor: default; + display: block; + padding: 1em 0.5rem; + position: fixed; + text-align: center; + width: 60%; + // height: 200px; + top: 50px; + left: 50%; + border-radius: 12px; + // margin-top: -100px; /* Negative half of height. */ + margin-left: -30%; /* Negative half of width. */ + visibility: hidden; + font-size: 2rem; + z-index: 100; + + &.show { + visibility: visible; /* Show the snackbar */ + } + + &:before { + // background: transparent; + // border: 12px solid transparent; + // content: ''; + // left: 50%; + // position: absolute; + // pointer-events: none; + // top: -24px; + // z-index: 1001; + + .vscode-light & { + border-bottom-color: var(--color-background--darken-075); + } + + .vscode-dark & { + border-bottom-color: var(--color-background--lighten-075); + } + } + .vscode-light & { + background-color: #cc5d1a; + color: #f2f2f2; + } + + .vscode-dark & { + background-color: #cc5d1a; + color: #f2f2f2; + } +} + /* Animations to fade the snackbar in and out */ @keyframes fadein { from { // top: 0; - opacity: 0; + opacity: 0.8; } to { // top: 30px; From 418acb64683c7439c4e8bac6fe252c247f58973a Mon Sep 17 00:00:00 2001 From: felix Date: Wed, 8 Jul 2020 02:33:13 -0400 Subject: [PATCH 6/7] Redid #18 for menu and command enablers/disablers. LeoInteg is now much more aware of Leo's states and only shows relevant commands Fixes #30 Adds hoist dehoist. Fixes Add hoist/dehoist commands #25 Move with arrow keys alone Fixes #43 Fixes Force redraw/refresh for icons to update in the outline after a configuration change #16 --- CHANGELOG.md | 1 + leoInteg.leo | 10 +-- leobridgeserver.py | 4 +- package.json | 69 +++++++++++------- src/constants.ts | 25 +++++-- src/extension.ts | 5 +- src/leoBody.ts | 4 +- src/leoBridge.ts | 2 +- src/leoDocuments.ts | 2 +- src/leoIntegration.ts | 119 +++++++----------------------- src/leoNode.ts | 35 +++++++-- src/leoOutline.ts | 45 ++++++++---- src/leoStates.ts | 166 ++++++++++++++++++++++++++++++++++++++++++ src/leoStatusBar.ts | 5 +- src/types.d.ts | 17 +++-- 15 files changed, 338 insertions(+), 171 deletions(-) create mode 100644 src/leoStates.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f1e22aa..bcaa5f4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 0.1.13 - Added support for precise focus placement, focus switch between tree/body. +- Made the extension more aware of the current selection state, to have strictly relevant buttons visible shown only. - Made the 'edit headline' hover icon removable, in order to enable 'Tab' keybinding to go from tree to body directly. - Added commands and keybindings for 'goto' operations 'hoist/dehoist' [#25](https://github.com/boltex/leointeg/issues/25) and other commands. [#30](https://github.com/boltex/leointeg/issues/30) - Added support for Leo-Style outline navigation. [#43](https://github.com/boltex/leointeg/issues/43) Has to be enabled with an option in the config settings: "Use Leo Tree Browsing" which makes arrow keys move selection instead of a cursor when focus is on the tree outline. diff --git a/leoInteg.leo b/leoInteg.leo index e8ed89e8..ff5e55dd 100644 --- a/leoInteg.leo +++ b/leoInteg.leo @@ -246,11 +246,7 @@ To contribute, see the official issues page for current list of 'TODO's at https return self.outputPNodes([]) # default empty array else: if self.commander.hoistStack: - w_p = self.commander.hoistStack[-1].p - if w_p: - return self.outputPNodes([w_p]) - else: - return self.outputPNodes([]) # default empty array + return self.outputPNodes([self.commander.hoistStack[-1].p]) else: return self.outputPNodes(self.yieldAllRootChildren()) # this outputs all Root Children @@ -466,7 +462,7 @@ if __name__ == '__main__': 'headline': stack_v.h, } for (stack_v, stack_childIndex) in p.stack], } - # TODO : (MAYBE) Convert all those booleans into an integer 'status' Flags + # TODO : Convert all those booleans into an 8 bit integer 'status' flag if bool(p.b): w_ap['hasBody'] = True if p.hasChildren(): @@ -1435,6 +1431,7 @@ wsPort = 32125 w_states["canUndo"] = self.commander.canUndo() w_states["canRedo"] = self.commander.canRedo() w_states["canDemote"] = self.commander.canDemote() + w_states["canPromote"] = self.commander.canPromote() w_states["canDehoist"] = self.commander.canDehoist() except Exception as e: @@ -1446,6 +1443,7 @@ wsPort = 32125 w_states["canUndo"] = False w_states["canRedo"] = False w_states["canDemote"] = False + w_states["canPromote"] = False w_states["canDehoist"] = False return self.sendLeoBridgePackage("states", w_states) diff --git a/leobridgeserver.py b/leobridgeserver.py index 71e655e3..53c40f7a 100644 --- a/leobridgeserver.py +++ b/leobridgeserver.py @@ -662,6 +662,7 @@ def getStates(self, p_package): w_states["canUndo"] = self.commander.canUndo() w_states["canRedo"] = self.commander.canRedo() w_states["canDemote"] = self.commander.canDemote() + w_states["canPromote"] = self.commander.canPromote() w_states["canDehoist"] = self.commander.canDehoist() except Exception as e: @@ -673,6 +674,7 @@ def getStates(self, p_package): w_states["canUndo"] = False w_states["canRedo"] = False w_states["canDemote"] = False + w_states["canPromote"] = False w_states["canDehoist"] = False return self.sendLeoBridgePackage("states", w_states) @@ -1204,7 +1206,7 @@ def p_to_ap(self, p): 'headline': stack_v.h, } for (stack_v, stack_childIndex) in p.stack], } - # TODO : (MAYBE) Convert all those booleans into an integer 'status' Flags + # TODO : Convert all those booleans into an 8 bit integer 'status' flag if bool(p.b): w_ap['hasBody'] = True if p.hasChildren(): diff --git a/package.json b/package.json index bea54058..f8943f39 100644 --- a/package.json +++ b/package.json @@ -844,7 +844,12 @@ "title": "Goto Next Clone" }, { - "command": "leointeg.gotoNextCloneFromOutline", + "command": "leointeg.gotoNextCloneSelection", + "category": "Leo", + "title": "Goto Next Clone" + }, + { + "command": "leointeg.gotoNextCloneSelectionFromOutline", "category": "Leo", "title": "Goto Next Clone" }, @@ -1019,11 +1024,11 @@ }, { "command": "leointeg.markSelection", - "when": "leoTreeOpened" + "when": "leoTreeOpened && !leoMarked" }, { "command": "leointeg.unmarkSelection", - "when": "leoTreeOpened" + "when": "leoTreeOpened && leoMarked" }, { "command": "leointeg.copyNodeSelection", @@ -1071,15 +1076,15 @@ }, { "command": "leointeg.promoteSelection", - "when": "leoTreeOpened" + "when": "leoTreeOpened && leoCanPromote" }, { "command": "leointeg.demoteSelection", - "when": "leoTreeOpened" + "when": "leoTreeOpened && leoCanDemote" }, { "command": "leointeg.sortChildrenSelection", - "when": "leoTreeOpened" + "when": "leoTreeOpened && leoChild" }, { "command": "leointeg.sortSiblingsSelection", @@ -1091,7 +1096,7 @@ }, { "command": "leointeg.refreshFromDiskSelection", - "when": "leoTreeOpened" + "when": "leoTreeOpened && leoAtFile" }, { "command": "leointeg.undo", @@ -1146,8 +1151,8 @@ "when": "leoTreeOpened" }, { - "command": "leointeg.gotoNextClone", - "when": "leoTreeOpened" + "command": "leointeg.gotoNextCloneSelection", + "when": "leoTreeOpened && leoCloned" }, { "command": "leointeg.markChangedItems", @@ -1213,6 +1218,14 @@ "command": "leointeg.contractAllFromOutline", "when": "false" }, + { + "command": "leointeg.gotoNextClone", + "when": "false" + }, + { + "command": "leointeg.gotoNextCloneSelectionFromOutline", + "when": "false" + }, { "command": "leointeg.editHeadline", "when": "false" @@ -1346,7 +1359,7 @@ "when": "false" }, { - "command": "leointeg.gotoNextCloneFromOutline", + "command": "leointeg.gotoNextCloneSelectionFromOutline", "when": "false" }, { @@ -1525,7 +1538,12 @@ }, { "command": "leointeg.hoistNode", - "when": "viewItem =~ /leoNode/", + "when": "viewItem =~ /leoNodeNotRoot/", + "group": "leoNodeContext1@2" + }, + { + "command": "leointeg.dehoist", + "when": "leoCanDehoist && viewItem =~ /leoNodeRoot/", "group": "leoNodeContext1@2" }, { @@ -1579,14 +1597,9 @@ "group": "leoNodeContext3@2" }, { - "command": "leointeg.promote", - "when": "leoTreeOpened && viewItem =~ /leoNode/", + "command": "leointeg.gotoNextClone", + "when": "leoTreeOpened && viewItem =~ /leoNodeCloned/", "group": "leoNodeContext3@3" - }, - { - "command": "leointeg.demote", - "when": "leoTreeOpened && viewItem =~ /leoNode/", - "group": "leoNodeContext3@4" } ] }, @@ -1602,12 +1615,12 @@ "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { - "command": "leointeg.gotoNextCloneFromOutline", + "command": "leointeg.gotoNextCloneSelectionFromOutline", "key": "alt+n", "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { - "command": "leointeg.gotoNextClone", + "command": "leointeg.gotoNextCloneSelection", "key": "alt+n", "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, @@ -1746,25 +1759,25 @@ "command": "leointeg.markSelection", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && !leoNodeMarked && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && !leoMarked && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.markSelectionFromOutline", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && !leoNodeMarked && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && !leoMarked && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.unmarkSelection", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && leoNodeMarked && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && leoMarked && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.unmarkSelectionFromOutline", "key": "ctrl+m", "mac": "cmd+m", - "when": "leoTreeOpened && leoNodeMarked && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && leoMarked && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.promoteSelection", @@ -1772,7 +1785,7 @@ "win": "ctrl+oem_4", "linux": "ctrl+[", "mac": "cmd+[BracketLeft]", - "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && leoCanPromote && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.promoteSelectionFromOutline", @@ -1780,7 +1793,7 @@ "win": "ctrl+oem_4", "linux": "ctrl+[", "mac": "cmd+[BracketLeft]", - "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && leoCanPromote && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.demoteSelection", @@ -1788,7 +1801,7 @@ "win": "ctrl+oem_6", "linux": "ctrl+]", "mac": "cmd+[BracketRight]", - "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && leoCanDemote && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.demoteSelectionFromOutline", @@ -1796,7 +1809,7 @@ "win": "ctrl+oem_6", "linux": "ctrl+]", "mac": "cmd+[BracketRight]", - "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && leoCanDemote && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineDownSelection", diff --git a/src/constants.ts b/src/constants.ts index 9507a66a..f4557e6f 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -162,12 +162,24 @@ export class Constants { LEO_CAN_UNDO: "leoCanUndo", LEO_CAN_REDO: "leoCanRedo", LEO_CAN_DEMOTE: "leoCanDemote", + LEO_CAN_PROMOTE: "leoCanPromote", LEO_CAN_DEHOIST: "leoCanDehoist", - // Flags for current selection in outline tree view + // 'states' flags about current selection, for visibility and commands availability + SELECTED_MARKED: "leoMarked", // no need for unmarked here, use !leoMarked + SELECTED_CLONE: "leoCloned", + SELECTED_DIRTY: "leoDirty", + SELECTED_EMPTY: "leoEmpty", + SELECTED_CHILD: "leoChild", // Has children + SELECTED_ATFILE: "LeoAtFile", // Can be refreshed + // Statusbar Flag 'keybindings in effect' LEO_SELECTED: "leoObjectSelected", // keybindings "On": Outline or body has focus - SELECTED_MARKED: "leoNodeMarked", // Selected node is marked - SELECTED_UNMARKED: "leoNodeUnmarked", // Selected node is unmarked - SELECTED_ATFILE: "leoNodeAtFile", // Selected node is an @file or @clean, etc... + // Context Flags for 'when' clauses, used concatenated, for each outline node + NODE_MARKED: "leoNodeMarked", // Selected node is marked + NODE_UNMARKED: "leoNodeUnmarked", // Selected node is unmarked (Needed for regexp) + NODE_ATFILE: "leoNodeAtFile", // Selected node is an @file or @clean, etc... + NODE_CLONED: "leoNodeCloned", + NODE_ROOT: "leoNodeRoot", + NODE_NOT_ROOT: "leoNodeNotRoot", // Flags for Leo documents tree view icons and hover node command buttons DOCUMENT_SELECTED_TITLED: "leoDocumentSelectedTitled", DOCUMENT_TITLED: "leoDocumentTitled", @@ -177,7 +189,7 @@ export class Constants { LEO_TREE_BROWSE: Constants.CONFIG.LEO_TREE_BROWSE, // Leo outline also in the explorer view TREE_IN_EXPLORER: Constants.CONFIG.TREE_IN_EXPLORER, // Leo outline also in the explorer view SHOW_OPEN_ASIDE: Constants.CONFIG.SHOW_OPEN_ASIDE, // Show 'open aside' in context menu - SHOW_EDIT: Constants.CONFIG.SHOW_EDIT, // Hover Icons on outline nodes + SHOW_EDIT: Constants.CONFIG.SHOW_EDIT, // Hover Icons on outline nodes SHOW_ARROWS: Constants.CONFIG.SHOW_ARROWS, // Hover Icons on outline nodes SHOW_ADD: Constants.CONFIG.SHOW_ADD, // Hover Icons on outline nodes SHOW_MARK: Constants.CONFIG.SHOW_MARK, // Hover Icons on outline nodes @@ -331,7 +343,8 @@ export class Constants { GOTO_PREV_VISIBLE: "gotoPrevVisible", GOTO_NEXT_MARKED: "gotoNextMarked", GOTO_NEXT_CLONE: "gotoNextClone", - GOTO_NEXT_CLONE_FO: "gotoNextCloneFromOutline", + GOTO_NEXT_CLONE_SELECTION: "gotoNextCloneSelection", + GOTO_NEXT_CLONE_SELECTION_FO: "gotoNextCloneSelectionFromOutline", CONTRACT_OR_GO_LEFT: "contractOrGoLeft", EXPAND_AND_GO_RIGHT: "expandAndGoRight", // * Leo Operations diff --git a/src/extension.ts b/src/extension.ts index 75e30de4..19002f13 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -124,8 +124,9 @@ export function activate(p_context: vscode.ExtensionContext) { [w_cmdPrefix + Constants.COMMANDS.GOTO_FIRST_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_FIRST_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_LAST_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_LAST_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_LAST_SIBLING, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_LAST_SIBLING, undefined, RefreshType.RefreshTreeAndBody, true)], - [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_CLONE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_CLONE, undefined, RefreshType.RefreshTreeAndBody, false)], - [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_CLONE_FO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_CLONE, undefined, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_CLONE, (p_node: LeoNode) => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_CLONE, p_node, RefreshType.RefreshTreeAndBody, true)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_CLONE_SELECTION, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_CLONE, undefined, RefreshType.RefreshTreeAndBody, false)], + [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_CLONE_SELECTION_FO, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_CLONE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_NEXT_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_NEXT_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], [w_cmdPrefix + Constants.COMMANDS.GOTO_PREV_VISIBLE, () => w_leoIntegration.nodeCommand(Constants.LEOBRIDGE.GOTO_PREV_VISIBLE, undefined, RefreshType.RefreshTreeAndBody, true)], diff --git a/src/leoBody.ts b/src/leoBody.ts index 31beb774..9bfb3e1b 100644 --- a/src/leoBody.ts +++ b/src/leoBody.ts @@ -130,7 +130,7 @@ export class LeoBodyProvider implements vscode.FileSystemProvider { public stat(p_uri: vscode.Uri): vscode.FileStat | Thenable { // TODO : Fix extraneous stat(...) call(s) - if (this._leoIntegration.fileOpenedReady) { + if (this._leoIntegration.leoStates.fileOpenedReady) { if (p_uri.fsPath.length === 1) { // p_uri.fsPath === '/' || p_uri.fsPath === '\\' // console.log('called stat on root'); return { type: vscode.FileType.Directory, ctime: 0, mtime: 0, size: 0 }; @@ -175,7 +175,7 @@ export class LeoBodyProvider implements vscode.FileSystemProvider { } public readFile(p_uri: vscode.Uri): Thenable { - if (this._leoIntegration.fileOpenedReady) { + if (this._leoIntegration.leoStates.fileOpenedReady) { if (p_uri.fsPath.length === 1) { // p_uri.fsPath === '/' || p_uri.fsPath === '\\' throw vscode.FileSystemError.FileIsADirectory(); } else { diff --git a/src/leoBridge.ts b/src/leoBridge.ts index 35439542..53bcb8f3 100644 --- a/src/leoBridge.ts +++ b/src/leoBridge.ts @@ -200,7 +200,7 @@ export class LeoBridge { console.log(`Websocket closed, code: ${p_event.code}`); this._rejectAction(`Websocket closed, code: ${p_event.code}`); // TODO : Implement a better connection error handling - if (this._leoIntegration.leoBridgeReady) { + if (this._leoIntegration.leoStates.leoBridgeReady) { this._leoIntegration.cancelConnect(`Websocket closed, code: ${p_event.code}`); } }; diff --git a/src/leoDocuments.ts b/src/leoDocuments.ts index 6d5aaebe..11a2c92a 100644 --- a/src/leoDocuments.ts +++ b/src/leoDocuments.ts @@ -30,7 +30,7 @@ export class LeoDocumentsProvider implements vscode.TreeDataProvider { // if called with element, or not ready, give back empty array as there won't be any children - if (this._leoIntegration.fileOpenedReady && !element) { + if (this._leoIntegration.leoStates.fileOpenedReady && !element) { // call action to get get list, and convert to LeoDocumentNode(s) array return this._leoIntegration.sendAction(Constants.LEOBRIDGE.GET_OPENED_FILES).then(p_package => { diff --git a/src/leoIntegration.ts b/src/leoIntegration.ts index ceafda96..65abd15d 100644 --- a/src/leoIntegration.ts +++ b/src/leoIntegration.ts @@ -14,6 +14,7 @@ import { LeoStatusBar } from "./leoStatusBar"; import { CommandStack } from "./commandStack"; import { LeoDocumentsProvider } from "./leoDocuments"; import { LeoDocumentNode } from "./leoDocumentNode"; +import { LeoStates } from "./leoStates"; /** * * Orchestrates Leo integration into vscode with treeview and file system providers @@ -25,72 +26,8 @@ export class LeoIntegration { private _leoBridgeReadyPromise: Promise | undefined; // Set when leoBridge has a leo controller ready private _currentOutlineTitle: string = Constants.GUI.TREEVIEW_TITLE_INTEGRATION; // Title has to be kept because it might need to be set (again) when either tree is first shown when switching visibility - private _leoBridgeReady: boolean = false; // Used along with executeCommand 'setContext' with Constants.CONTEXT_FLAGS.BRIDGE_READY - get leoBridgeReady(): boolean { - return this._leoBridgeReady; - } - set leoBridgeReady(p_value: boolean) { - this._leoBridgeReady = p_value; - utils.setContext(Constants.CONTEXT_FLAGS.BRIDGE_READY, p_value); - } - - private _fileOpenedReady: boolean = false; // Used along with executeCommand 'setContext' with Constants.CONTEXT_FLAGS.TREE_OPENED - get fileOpenedReady(): boolean { - return this._fileOpenedReady; - } - set fileOpenedReady(p_value: boolean) { - this._fileOpenedReady = p_value; - utils.setContext(Constants.CONTEXT_FLAGS.TREE_OPENED, p_value); - this._setTreeViewTitle( - p_value ? Constants.GUI.TREEVIEW_TITLE : Constants.GUI.TREEVIEW_TITLE_INTEGRATION - ); - } - - // * States used in UI button visibility: changed, can undo/redo, can demote and can dehoist. - private _leoChanged: boolean = false; - get leoChanged(): boolean { - return this._leoChanged; - } - set leoChanged(p_value: boolean) { - this._leoChanged = p_value; - utils.setContext(Constants.CONTEXT_FLAGS.LEO_CHANGED, p_value); - } - - private _leoCanUndo: boolean = false; - get leoCanUndo(): boolean { - return this._leoCanUndo; - } - set leoCanUndo(p_value: boolean) { - this._leoCanUndo = p_value; - utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_UNDO, p_value); - } - - private _leoCanRedo: boolean = false; - get leoCanRedo(): boolean { - return this._leoCanRedo; - } - set leoCanRedo(p_value: boolean) { - this._leoCanRedo = p_value; - utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_REDO, p_value); - } - - private _leoCanDemote: boolean = false; - get leoCanDemote(): boolean { - return this._leoCanDemote; - } - set leoCanDemote(p_value: boolean) { - this._leoCanDemote = p_value; - utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_DEMOTE, p_value); - } - - private _leoCanDehoist: boolean = false; - get leoCanDehoist(): boolean { - return this._leoCanDehoist; - } - set leoCanDehoist(p_value: boolean) { - this._leoCanDehoist = p_value; - utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_DEHOIST, p_value); - } + // * State flags + public leoStates: LeoStates; // * Frontend command stack private _commandStack: CommandStack; @@ -197,6 +134,9 @@ export class LeoIntegration { }; constructor(private _context: vscode.ExtensionContext) { + // * Setup States + this.leoStates = new LeoStates(_context, this); + // * Get configuration settings this.config = new Config(_context, this); this.config.buildFromSavedSettings(); @@ -321,7 +261,7 @@ export class LeoIntegration { * * Initiate a connection to the leoBridge server, then show view title, log pane, and set 'bridge ready' flags. */ public connect(): void { - if (this.leoBridgeReady || this._leoIsConnecting) { + if (this.leoStates.leoBridgeReady || this._leoIsConnecting) { vscode.window.showInformationMessage(Constants.USER_MESSAGES.ALREADY_CONNECTED); return; } @@ -333,7 +273,7 @@ export class LeoIntegration { if (p_package.id !== 1) { this.cancelConnect(Constants.USER_MESSAGES.CONNECT_ERROR); } else { - this.leoBridgeReady = true; + this.leoStates.leoBridgeReady = true; utils.setContext(Constants.CONTEXT_FLAGS.BRIDGE_READY, true); this.showLogPane(); if (!this.config.connectToServerAutomatically) { @@ -357,13 +297,13 @@ export class LeoIntegration { */ public cancelConnect(p_message?: string): void { // 'disconnect error' versus 'failed to connect' - if (this.leoBridgeReady) { + if (this.leoStates.leoBridgeReady) { vscode.window.showErrorMessage(p_message ? p_message : Constants.USER_MESSAGES.DISCONNECTED); } else { vscode.window.showInformationMessage(p_message ? p_message : Constants.USER_MESSAGES.DISCONNECTED); } - this.fileOpenedReady = false; - this.leoBridgeReady = false; + this.leoStates.fileOpenedReady = false; + this.leoStates.leoBridgeReady = false; this._leoBridgeReadyPromise = undefined; this._leoStatusBar.update(false); this._refreshOutline(RevealType.RevealSelect); @@ -389,7 +329,7 @@ export class LeoIntegration { * @param p_config A config object containing all the configuration settings */ public sendConfigToServer(p_config: ConfigMembers): void { - if (this.fileOpenedReady) { + if (this.leoStates.fileOpenedReady) { this.sendAction(Constants.LEOBRIDGE.APPLY_CONFIG, JSON.stringify(p_config)).then(p_package => { // Back from applying configuration to leobridgeserver.py }); @@ -402,14 +342,9 @@ export class LeoIntegration { private _triggerGetStates(): void { // Debounced timer has triggered so perform getStates action this._leoDocumentsProvider.refreshTreeRoot(); - this.sendAction(Constants.LEOBRIDGE.GET_STATES).then((p_package: LeoBridgePackage) => { if (p_package.states) { - this.leoChanged = p_package.states.changed; - this.leoCanUndo = p_package.states.canUndo; - this.leoCanRedo = p_package.states.canRedo; - this.leoCanDemote = p_package.states.canDemote; - this.leoCanDehoist = p_package.states.canDehoist; + this.leoStates.leoStateFlags(p_package.states); } }); } @@ -438,7 +373,7 @@ export class LeoIntegration { * * Setup leoInteg's UI for having no opened Leo documents */ private _setupNoOpenedLeoDocument(): void { - this.fileOpenedReady = false; + this.leoStates.fileOpenedReady = false; this._bodyTextDocument = undefined; this.lastSelectedNode = undefined; this._refreshOutline(RevealType.RevealSelectFocus); @@ -467,10 +402,10 @@ export class LeoIntegration { this._bodyFileSystemStarted = true; } // * Startup flag - this.fileOpenedReady = true; + this.leoStates.fileOpenedReady = true; // * First valid redraw of tree along with the selected node and its body this._refreshOutline(RevealType.RevealSelectFocus); // p_revealSelection flag set - // this._setTreeViewTitle(Constants.GUI.TREEVIEW_TITLE); // ? Maybe unused when used with welcome content + // this.setTreeViewTitle(Constants.GUI.TREEVIEW_TITLE); // ? Maybe unused when used with welcome content // * First StatusBar appearance this._leoStatusBar.show(); // Just selected a node // * Show leo log pane @@ -521,7 +456,7 @@ export class LeoIntegration { private _onTreeViewVisibilityChanged(p_event: vscode.TreeViewVisibilityChangeEvent, p_explorerView: boolean): void { if (p_event.visible) { this._lastVisibleTreeView = p_explorerView ? this._leoTreeExplorerView : this._leoTreeStandaloneView; - this._setTreeViewTitle(); + this.setTreeViewTitle(); this._needLastSelectedRefresh = true; // Its a new node in a new tree so refresh lastSelectedNode too this._refreshOutline(RevealType.RevealSelect); } @@ -685,7 +620,7 @@ export class LeoIntegration { * * Refresh tree for node hover icons refresh only */ public configTreeRefresh(): void { - if (this.fileOpenedReady && this.lastSelectedNode) { + if (this.leoStates.fileOpenedReady && this.lastSelectedNode) { this._revealType = RevealType.RevealSelect; this._preventShowBody = true; this._leoTreeDataProvider.refreshTreeRoot(); @@ -749,6 +684,7 @@ export class LeoIntegration { * @param p_leoNode The node that was detected as the selected node in Leo */ private _apToLeoNodeConvertReveal(p_leoNode: LeoNode): void { + this.leoStates.selectedNodeFlags(p_leoNode); // First setup flags for selecting and focusing based on the current reveal type needed const w_selectFlag = this._revealType >= RevealType.RevealSelect; // at least RevealSelect let w_focusFlag = this._revealType >= RevealType.RevealSelectFocus; // at least RevealSelectFocus @@ -861,6 +797,7 @@ export class LeoIntegration { if (p_aside && p_node !== this.lastSelectedNode) { this._revealTreeViewNode(p_node, { select: true, focus: false }); // no need to set focus: tree selection is set to right-click position } + this.leoStates.selectedNodeFlags(p_node); // TODO : #39 @boltex Save and restore selection, along with cursor position, from selection state saved in each node (or gnx array) this._leoStatusBar.update(true); // Just selected a node directly, or via expand/collapse const w_showBodyKeepFocus = p_aside ? this.config.treeKeepFocusWhenAside : this.config.treeKeepFocus; @@ -1151,9 +1088,9 @@ export class LeoIntegration { * @param p_fromOutlineSignifies that the focus was, and should be brought back to, the outline */ public saveAsLeoFile(p_fromOutline?: boolean): void { - if (!this.fileOpenedReady || this._isBusy()) { return; } // Warn user to wait for end of busy state + if (!this.leoStates.fileOpenedReady || this._isBusy()) { return; } // Warn user to wait for end of busy state // TODO : Implement & support multiple simultaneous files - if (this.fileOpenedReady) { + if (this.leoStates.fileOpenedReady) { if (this.lastSelectedNode) { this.triggerBodySave(true) .then(() => { @@ -1175,9 +1112,9 @@ export class LeoIntegration { * @param p_fromOutlineSignifies that the focus was, and should be brought back to, the outline */ public saveLeoFile(p_fromOutline?: boolean): void { - if (!this.fileOpenedReady || this._isBusy()) { return; } // Warn user to wait for end of busy state + if (!this.leoStates.fileOpenedReady || this._isBusy()) { return; } // Warn user to wait for end of busy state // TODO : Specify which file when supporting multiple simultaneous opened Leo files - if (this.fileOpenedReady) { + if (this.leoStates.fileOpenedReady) { if (this.lastSelectedNode && this._isCurrentFileNamed()) { this.triggerBodySave(true) .then(() => { @@ -1195,7 +1132,7 @@ export class LeoIntegration { * * Show switch document 'QuickPick' dialog and switch file if selection is made, or just return if no files are opened. */ public switchLeoFile(): void { - if (!this.fileOpenedReady || this._isBusy()) { return; } // Warn user to wait for end of busy state + if (!this.leoStates.fileOpenedReady || this._isBusy()) { return; } // Warn user to wait for end of busy state // get list and show dialog to user, even if there's only one...but at least one! // TODO : p_package members names should be made into constants // TODO : Fix / Cleanup opened body panes close before reopening when switching @@ -1255,7 +1192,7 @@ export class LeoIntegration { */ public closeLeoFile(): void { if (this._isBusy()) { return; } // Warn user to wait for end of busy state - if (this.fileOpenedReady) { + if (this.leoStates.fileOpenedReady) { this.triggerBodySave(true) .then(() => { return this.sendAction(Constants.LEOBRIDGE.CLOSE_FILE, JSON.stringify({ forced: false })); @@ -1369,7 +1306,7 @@ export class LeoIntegration { * * Set the outline pane top bar string message * @param p_title new string to replace the current title */ - private _setTreeViewTitle(p_title?: string): void { + public setTreeViewTitle(p_title?: string): void { if (p_title) { this._currentOutlineTitle = p_title; } @@ -1393,7 +1330,7 @@ export class LeoIntegration { * * StatusBar click handler */ public statusBarOnClick(): void { - if (this.fileOpenedReady) { + if (this.leoStates.fileOpenedReady) { this.switchLeoFile(); } else { this.showLeoCommands(); diff --git a/src/leoNode.ts b/src/leoNode.ts index 90593b10..fda26ccd 100644 --- a/src/leoNode.ts +++ b/src/leoNode.ts @@ -11,6 +11,8 @@ export class LeoNode extends vscode.TreeItem { public cursorSelection: any; // TODO : #39 @boltex Keep body's cursor and selection position from vscode to get it back public contextValue: string; // * Context string is checked in package.json with 'when' clauses + public isRoot: boolean = false; + constructor( public label: string, // Node headline public gnx: string, @@ -26,7 +28,7 @@ export class LeoNode extends vscode.TreeItem { private _id: string ) { super(label, collapsibleState); - this.contextValue = this._getContextValue(marked, atFile); + this.contextValue = this._getNodeContextValue(); this.command = { command: Constants.NAME + "." + Constants.COMMANDS.SELECT_NODE, title: '', @@ -64,17 +66,34 @@ export class LeoNode extends vscode.TreeItem { this.marked = p_node.marked; this.atFile = p_node.atFile; this.hasBody = p_node.hasBody; - this.contextValue = this._getContextValue(p_node.marked, p_node.atFile); + this.isRoot = p_node.isRoot; + this.contextValue = this._getNodeContextValue(); return this; } - private _getContextValue(p_marked: boolean, p_atFile: boolean): string { - let w_contextValue = Constants.CONTEXT_FLAGS.SELECTED_UNMARKED; // * Start it with 'leoNodeMarked' or 'leoNodeUnmarked' - if (p_marked) { - w_contextValue = Constants.CONTEXT_FLAGS.SELECTED_MARKED; + /** + * * Set this node as the root not for context flags purposes + */ + public setRoot(): void { + this.isRoot = true; + this.contextValue = this._getNodeContextValue(); + } + + private _getNodeContextValue(): string { + let w_contextValue = Constants.CONTEXT_FLAGS.NODE_UNMARKED; // * Start it with 'leoNodeMarked' or 'leoNodeUnmarked' + if (this.marked) { + w_contextValue = Constants.CONTEXT_FLAGS.NODE_MARKED; + } + if (this.atFile) { + w_contextValue += Constants.CONTEXT_FLAGS.NODE_ATFILE; // * then append 'leoNodeAtFile' to existing if needed + } + if (this.cloned) { + w_contextValue += Constants.CONTEXT_FLAGS.NODE_CLONED; // * then append 'leoNodeCloned' to existing if needed } - if (p_atFile) { - w_contextValue += Constants.CONTEXT_FLAGS.SELECTED_ATFILE; // * then append 'leoNodeAtFile' to existing if needed + if (this.isRoot) { + w_contextValue += Constants.CONTEXT_FLAGS.NODE_ROOT; + } else { + w_contextValue += Constants.CONTEXT_FLAGS.NODE_NOT_ROOT; } return w_contextValue; } diff --git a/src/leoOutline.ts b/src/leoOutline.ts index 279c479e..5357ce62 100644 --- a/src/leoOutline.ts +++ b/src/leoOutline.ts @@ -3,14 +3,13 @@ import { LeoIntegration } from "./leoIntegration"; import { LeoNode } from "./leoNode"; import { ProviderResult } from "vscode"; import { Constants } from "./constants"; +import { LeoBridgePackage } from "./types"; /** * * Leo outline implemented as a tree view with this TreeDataProvider implementation */ export class LeoOutlineProvider implements vscode.TreeDataProvider { - // TODO : p_package members names should be made into constants - private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; @@ -39,7 +38,7 @@ export class LeoOutlineProvider implements vscode.TreeDataProvider { if (this._refreshSingleNodeFlag) { this._refreshSingleNodeFlag = false; return this._leoIntegration.sendAction(Constants.LEOBRIDGE.GET_PNODE, element.apJson) - .then((p_package) => { + .then((p_package: LeoBridgePackage) => { const w_node = this._leoIntegration.apToLeoNode(p_package.node!, true, element); return element.copyProperties(w_node); }); @@ -49,29 +48,43 @@ export class LeoOutlineProvider implements vscode.TreeDataProvider { } public getChildren(element?: LeoNode): Thenable { - if (this._leoIntegration.fileOpenedReady) { - return this._leoIntegration.sendAction(Constants.LEOBRIDGE.GET_CHILDREN, element ? element.apJson : "null").then((p_package) => { - return this._leoIntegration.arrayToLeoNodesArray(p_package.nodes!); - }); - } else { + if (!this._leoIntegration.leoStates.fileOpenedReady) { return Promise.resolve([]); // Defaults to an empty list of children } + if (element) { + return this._leoIntegration.sendAction(Constants.LEOBRIDGE.GET_CHILDREN, element.apJson) + .then((p_package: LeoBridgePackage) => { + return this._leoIntegration.arrayToLeoNodesArray(p_package.nodes!); + }); + } else { + return this._leoIntegration.sendAction(Constants.LEOBRIDGE.GET_CHILDREN, "null") + .then((p_package: LeoBridgePackage) => { + const w_nodes = this._leoIntegration.arrayToLeoNodesArray(p_package.nodes!); + + if (w_nodes && w_nodes.length === 1) { + w_nodes[0].setRoot(); + } + return w_nodes; + }); + } } + public getParent(element: LeoNode): ProviderResult | null { // * This method should be implemented in order to access reveal API. // ! But it should NOT have to be called because we will only try to 'select' already revealed nodes console.log('ERROR! GET PARENT CALLED! on: ', element.label); - if (this._leoIntegration.fileOpenedReady) { - return this._leoIntegration.sendAction(Constants.LEOBRIDGE.GET_PARENT, element ? element.apJson : "null").then((p_package) => { - if (p_package.node === null) { - return null; - } else { - return this._leoIntegration.apToLeoNode(p_package.node!); - } - }); + if (this._leoIntegration.leoStates.fileOpenedReady) { + return this._leoIntegration.sendAction(Constants.LEOBRIDGE.GET_PARENT, element ? element.apJson : "null") + .then((p_package: LeoBridgePackage) => { + if (p_package.node === null) { + return null; + } else { + return this._leoIntegration.apToLeoNode(p_package.node!); + } + }); } else { return null; // Default gives no parent } diff --git a/src/leoStates.ts b/src/leoStates.ts new file mode 100644 index 00000000..a929b128 --- /dev/null +++ b/src/leoStates.ts @@ -0,0 +1,166 @@ +import * as vscode from "vscode"; +import * as utils from "./utils"; +import { Constants } from "./constants"; +import { LeoIntegration } from "./leoIntegration"; +import { LeoNode } from "./leoNode"; +import { LeoPackageStates } from "./types"; + +/** + * * Holds state flags used to restrict command and icon availability + */ +export class LeoStates { + + private _leoBridgeReady: boolean = false; // Used along with executeCommand 'setContext' with Constants.CONTEXT_FLAGS.BRIDGE_READY + get leoBridgeReady(): boolean { + return this._leoBridgeReady; + } + set leoBridgeReady(p_value: boolean) { + this._leoBridgeReady = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.BRIDGE_READY, p_value); + } + + private _fileOpenedReady: boolean = false; // Used along with executeCommand 'setContext' with Constants.CONTEXT_FLAGS.TREE_OPENED + get fileOpenedReady(): boolean { + return this._fileOpenedReady; + } + set fileOpenedReady(p_value: boolean) { + this._fileOpenedReady = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.TREE_OPENED, p_value); + this._leoIntegration.setTreeViewTitle( + p_value ? Constants.GUI.TREEVIEW_TITLE : Constants.GUI.TREEVIEW_TITLE_INTEGRATION + ); + } + + // * 'states' flags for currently opened tree view + private _leoChanged: boolean = false; + get leoChanged(): boolean { + return this._leoChanged; + } + set leoChanged(p_value: boolean) { + this._leoChanged = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.LEO_CHANGED, p_value); + } + + private _leoCanUndo: boolean = false; + get leoCanUndo(): boolean { + return this._leoCanUndo; + } + set leoCanUndo(p_value: boolean) { + this._leoCanUndo = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_UNDO, p_value); + } + + private _leoCanRedo: boolean = false; + get leoCanRedo(): boolean { + return this._leoCanRedo; + } + set leoCanRedo(p_value: boolean) { + this._leoCanRedo = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_REDO, p_value); + } + + private _leoCanDemote: boolean = false; + get leoCanDemote(): boolean { + return this._leoCanDemote; + } + set leoCanDemote(p_value: boolean) { + this._leoCanDemote = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_DEMOTE, p_value); + } + + private _leoCanPromote: boolean = false; + get leoCanPromote(): boolean { + return this._leoCanPromote; + } + set leoCanPromote(p_value: boolean) { + this._leoCanPromote = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_PROMOTE, p_value); + } + + private _leoCanDehoist: boolean = false; + get leoCanDehoist(): boolean { + return this._leoCanDehoist; + } + set leoCanDehoist(p_value: boolean) { + this._leoCanDehoist = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.LEO_CAN_DEHOIST, p_value); + } + + // * 'states' flags about current selection, for visibility and commands availability + private _leoMarked: boolean = false; + get leoMarked(): boolean { + return this._leoMarked; + } + set leoMarked(p_value: boolean) { + this._leoMarked = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.SELECTED_MARKED, p_value); + } + + private _leoCloned: boolean = false; + get leoCloned(): boolean { + return this._leoCloned; + } + set leoCloned(p_value: boolean) { + this._leoCloned = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.SELECTED_CLONE, p_value); + } + + private _leoDirty: boolean = false; + get leoDirty(): boolean { + return this._leoDirty; + } + set leoDirty(p_value: boolean) { + this._leoDirty = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.SELECTED_DIRTY, p_value); + } + + private _leoEmpty: boolean = false; + get leoEmpty(): boolean { + return this._leoEmpty; + } + set leoEmpty(p_value: boolean) { + this._leoEmpty = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.SELECTED_EMPTY, p_value); + } + + private _leoChild: boolean = false; + get leoChild(): boolean { + return this._leoChild; + } + set leoChild(p_value: boolean) { + this._leoChild = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.SELECTED_CHILD, p_value); + } + + private _leoAtFile: boolean = false; + get leoAtFile(): boolean { + return this._leoAtFile; + } + set leoAtFile(p_value: boolean) { + this._leoAtFile = p_value; + utils.setContext(Constants.CONTEXT_FLAGS.SELECTED_ATFILE, p_value); + } + + constructor( + private _context: vscode.ExtensionContext, + private _leoIntegration: LeoIntegration + ) { } + + public selectedNodeFlags(p_node: LeoNode): void { + this.leoMarked = p_node.marked; + this.leoCloned = p_node.cloned; + this.leoDirty = p_node.dirty; + this.leoEmpty = !p_node.hasBody; + this.leoChild = !(p_node.collapsibleState === vscode.TreeItemCollapsibleState.None); + this.leoAtFile = p_node.atFile; + } + + public leoStateFlags(p_states: LeoPackageStates): void { + this.leoChanged = p_states.changed; + this.leoCanUndo = p_states.canUndo; + this.leoCanRedo = p_states.canRedo; + this.leoCanDemote = p_states.canDemote; + this.leoCanPromote = p_states.canPromote; + this.leoCanDehoist = p_states.canDehoist; + } +} \ No newline at end of file diff --git a/src/leoStatusBar.ts b/src/leoStatusBar.ts index 79a83e31..52c7095e 100644 --- a/src/leoStatusBar.ts +++ b/src/leoStatusBar.ts @@ -13,7 +13,8 @@ export class LeoStatusBar { private _updateStatusBarTimeout: NodeJS.Timeout | undefined; private _string: string = ""; // Use this string with indicator, using this will replace the default from config - private _leoObjectSelected: boolean = false; // Represents having focus on a leo body + // * Represents having focus on a leo tree, body or document panel to enable leo keybindings + private _leoObjectSelected: boolean = false; set leoObjectSelected(p_value: boolean) { this._leoObjectSelected = p_value; } @@ -96,7 +97,7 @@ export class LeoStatusBar { } utils.setContext(Constants.CONTEXT_FLAGS.LEO_SELECTED, !!this.leoObjectSelected); this._leoStatusBarItem.text = Constants.GUI.STATUSBAR_INDICATOR + (this._string ? this._string : this._leoIntegration.config.statusBarString); - if (this.leoObjectSelected && this._leoIntegration.fileOpenedReady) { // * Also check in constructor for statusBar properties (the createStatusBarItem call itself) + if (this.leoObjectSelected && this._leoIntegration.leoStates.fileOpenedReady) { // * Also check in constructor for statusBar properties (the createStatusBarItem call itself) this._leoStatusBarItem.color = "#" + this._leoIntegration.config.statusBarColor; this._leoStatusBarItem.tooltip = Constants.USER_MESSAGES.STATUSBAR_TOOLTIP_ON; } else { diff --git a/src/types.d.ts b/src/types.d.ts index c13a7fde..a89a8959 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -98,6 +98,15 @@ export interface ArchivedPosition { }[]; // for (stack_v, stack_childIndex) in p.stack] } +export interface LeoPackageStates { + changed: boolean; + canUndo: boolean; + canRedo: boolean; + canDemote: boolean; + canPromote: boolean; + canDehoist: boolean; +} + /** * * Main JSON information package format used between leointeg and Leo */ @@ -109,13 +118,7 @@ export interface LeoBridgePackage { bodyData?: string; node?: ArchivedPosition; nodes?: ArchivedPosition[]; - states?: { - changed: boolean; - canUndo: boolean; - canRedo: boolean; - canDemote: boolean; - canDehoist: boolean; - }, + states?: LeoPackageStates; closed?: { total: number; filename?: string; From 94f457f2ff0ca4857ddc38c7979a4e5fab3eafea Mon Sep 17 00:00:00 2001 From: felix Date: Wed, 8 Jul 2020 02:37:46 -0400 Subject: [PATCH 7/7] Tuned up permissions for some keyboard commands for rapid chains of commands --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index f8943f39..64aa7147 100644 --- a/package.json +++ b/package.json @@ -1785,7 +1785,7 @@ "win": "ctrl+oem_4", "linux": "ctrl+[", "mac": "cmd+[BracketLeft]", - "when": "leoTreeOpened && leoCanPromote && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.promoteSelectionFromOutline", @@ -1793,7 +1793,7 @@ "win": "ctrl+oem_4", "linux": "ctrl+[", "mac": "cmd+[BracketLeft]", - "when": "leoTreeOpened && leoCanPromote && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.demoteSelection", @@ -1801,7 +1801,7 @@ "win": "ctrl+oem_6", "linux": "ctrl+]", "mac": "cmd+[BracketRight]", - "when": "leoTreeOpened && leoCanDemote && editorTextFocus && resourceScheme == leo" + "when": "leoTreeOpened && editorTextFocus && resourceScheme == leo" }, { "command": "leointeg.demoteSelectionFromOutline", @@ -1809,7 +1809,7 @@ "win": "ctrl+oem_6", "linux": "ctrl+]", "mac": "cmd+[BracketRight]", - "when": "leoTreeOpened && leoCanDemote && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" + "when": "leoTreeOpened && sideBarFocus && focusedView =~ /leoIntegration|leoDocuments/" }, { "command": "leointeg.moveOutlineDownSelection",