From 1ab8388c1de518f3aa528ab9006fe35c6917a8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20H=C3=A4usler?= Date: Mon, 19 Aug 2019 13:06:27 +0200 Subject: [PATCH] Cycle through tabs (#1283) * Cycle through tabs * Add cycle backwards alias --- docs/KEYBINDINGS.md | 175 ++++++++++++++------------- src/main/keyboard/shortcutHandler.js | 22 ++-- src/main/menu/index.js | 34 +++++- src/renderer/pages/app.vue | 1 + src/renderer/store/editor.js | 39 ++++++ 5 files changed, 180 insertions(+), 91 deletions(-) diff --git a/docs/KEYBINDINGS.md b/docs/KEYBINDINGS.md index e3faf495..782da6eb 100644 --- a/docs/KEYBINDINGS.md +++ b/docs/KEYBINDINGS.md @@ -32,103 +32,114 @@ Here is an example: **Mark Text menu (macOS only):** -| Id | Description | -| ----------------- | --------------------------------------- | -| `mtHide` | Hide Mark Text | -| `mtHideOthers` | Hide all other windows except Mark Text | -| `filePreferences` | Open settings window | -| `fileQuit` | Quit Mark Text | +| Id | Default | Description | +| ----------------- | ---------------------------------------------- | --------------------------------------- | +| `mtHide` | Command+H | Hide Mark Text | +| `mtHideOthers` | Command+Alt+H | Hide all other windows except Mark Text | +| `filePreferences` | Command+, | Open settings window | +| `fileQuit` | Command+Q | Quit Mark Text | **File menu:** -| Id | Description | -|:----------------- | ----------------------------------------- | -| `fileNewFile` | New file | -| `fileNewTab` | New tab | -| `fileOpenFile` | Open markdown file | -| `fileOpenFolder` | Open folder | -| `fileSave` | Save | -| `fileSaveAs` | Save as... | -| `filePreferences` | Open settings window (Linux/Windows only) | -| `fileCloseTab` | Close tab | -| `fileCloseWindow` | Close window | -| `fileQuit` | Quit Mark Text (Linux/Windows only) | +| Id | Default | Description | +|:----------------- | -------------------------------------------------- | ----------------------------------------- | +| `fileNewFile` | CmdOrCtrl+N | New file | +| `fileNewTab` | CmdOrCtrl+T | New tab | +| `fileOpenFile` | CmdOrCtrl+O | Open markdown file | +| `fileOpenFolder` | CmdOrCtrl+Shift+O | Open folder | +| `fileSave` | CmdOrCtrl+S | Save | +| `fileSaveAs` | CmdOrCtrl+Shift+S | Save as... | +| `filePrint` | Ctrl+P | Print current tab | +| `filePreferences` | Ctrl+, | Open settings window (Linux/Windows only) | +| `fileCloseTab` | CmdOrCtrl+W | Close tab | +| `fileCloseWindow` | CmdOrCtrl+Shift+W | Close window | +| `fileQuit` | CmdOrCtrl+Q | Quit Mark Text (Linux/Windows only) | **Edit menu:** -| Id | Description | -|:--------------------- | ----------------------------------------------- | -| `editUndo` | Undo last operation | -| `editRedo` | Redo last operation | -| `editCut` | Cut selected text | -| `editCopy` | Copy selected text | -| `editPaste` | Paste text | -| `editCopyAsMarkdown` | Copy selected text as markdown | -| `editCopyAsPlaintext` | Copy selected text as plaintext | -| `editSelectAll` | Select all text of the document | -| `editDuplicate` | Duplicate the current paragraph | -| `editCreateParagraph` | Create a new paragraph after the current one | -| `editDeleteParagraph` | Delete current paragraph | -| `editFind` | Find information in the document | -| `editFindNext` | Continue the search and find the next match | -| `editFindPrevious` | Continue the search and find the previous match | -| `editReplace` | Replace the information with a replacement | -| `editAidou` | Show Aidou dialog | -| `editScreenshot` | Get the screenshot | +| Id | Default | Description | +|:--------------------- | -------------------------------------------------- | ----------------------------------------------- | +| `editUndo` | CmdOrCtrl+Z | Undo last operation | +| `editRedo` | CmdOrCtrl+Shift+Z | Redo last operation | +| `editCut` | CmdOrCtrl+X | Cut selected text | +| `editCopy` | CmdOrCtrl+C | Copy selected text | +| `editPaste` | CmdOrCtrl+V | Paste text | +| `editCopyAsMarkdown` | CmdOrCtrl+Shift+C | Copy selected text as markdown | +| `editCopyAsPlaintext` | CmdOrCtrl+Shift+V | Copy selected text as plaintext | +| `editSelectAll` | CmdOrCtrl+A | Select all text of the document | +| `editDuplicate` | CmdOrCtrl+Shift+P | Duplicate the current paragraph | +| `editCreateParagraph` | CmdOrCtrl+Shift+N | Create a new paragraph after the current one | +| `editDeleteParagraph` | CmdOrCtrl+Shift+D | Delete current paragraph | +| `editFind` | CmdOrCtrl+F | Find information in the document | +| `editFindNext` | CmdOrCtrl+Alt+U | Continue the search and find the next match | +| `editFindPrevious` | CmdOrCtrl+Shift+U | Continue the search and find the previous match | +| `editReplace` | CmdOrCtrl+Alt+F | Replace the information with a replacement | +| `editAidou` | CmdOrCtrl+/ | Show Aidou dialog | +| `editScreenshot` | Command+Alt+A | Get the screenshot (macOS only) | **Paragraph menu:** -| Id | Description | -| -------------------------- | ---------------------------------------- | -| `paragraphHeading1` | Set line as heading 1 | -| `paragraphHeading2` | Set line as heading 2 | -| `paragraphHeading3` | Set line as heading 3 | -| `paragraphHeading4` | Set line as heading 4 | -| `paragraphHeading5` | Set line as heading 5 | -| `paragraphHeading6` | Set line as heading 6 | -| `paragraphUpgradeHeading` | Upgrade a heading | -| `paragraphDegradeHeading` | Degrade a heading | -| `paragraphTable` | Insert a table | -| `paragraphCodeFence` | Insert a code block | -| `paragraphQuoteBlock` | Insert a quote block | -| `paragraphMathBlock` | Insert a math block | -| `paragraphHtmlBlock` | Insert a HTML block | -| `paragraphOrderList` | Insert a ordered list | -| `paragraphBulletList` | Insert a unordered list | -| `paragraphTaskList` | Insert a task list | -| `paragraphLooseListItem` | Convert a list item to a loose list item | -| `paragraphParagraph` | Convert a heading to a paragraph | -| `paragraphHorizontalLine` | Add a horizontal line | -| `paragraphYAMLFrontMatter` | Insert a YAML frontmatter block | +| Id | Default | Description | +| -------------------------- | -------------------------------------------------- | ------------------------------------------------- | +| `paragraphHeading1` | CmdOrCtrl+1 | Set line as heading 1 | +| `paragraphHeading2` | CmdOrCtrl+2 | Set line as heading 2 | +| `paragraphHeading3` | CmdOrCtrl+3 | Set line as heading 3 | +| `paragraphHeading4` | CmdOrCtrl+4 | Set line as heading 4 | +| `paragraphHeading5` | CmdOrCtrl+5 | Set line as heading 5 | +| `paragraphHeading6` | CmdOrCtrl+6 | Set line as heading 6 | +| `paragraphUpgradeHeading` | CmdOrCtrl+= | Upgrade a heading | +| `paragraphDegradeHeading` | CmdOrCtrl+- | Degrade a heading | +| `paragraphTable` | CmdOrCtrl+T | Insert a table | +| `paragraphCodeFence` | CmdOrCtrl+Alt+C | Insert a code block | +| `paragraphQuoteBlock` | CmdOrCtrl+Alt+Q | Insert a quote block | +| `paragraphMathBlock` | CmdOrCtrl+Alt+M | Insert a math block | +| `paragraphHtmlBlock` | CmdOrCtrl+Alt+J/H | Insert a HTML block (`J` on macOS, `H` otherwise) | +| `paragraphOrderList` | CmdOrCtrl+Alt+O | Insert a ordered list | +| `paragraphBulletList` | CmdOrCtrl+Alt+U | Insert a unordered list | +| `paragraphTaskList` | CmdOrCtrl+Alt+X | Insert a task list | +| `paragraphLooseListItem` | CmdOrCtrl+Alt+L | Convert a list item to a loose list item | +| `paragraphParagraph` | CmdOrCtrl+0 | Convert a heading to a paragraph | +| `paragraphHorizontalLine` | CmdOrCtrl+Alt+- | Add a horizontal line | +| `paragraphYAMLFrontMatter` | CmdOrCtrl+Alt+Y | Insert a YAML frontmatter block | **Format menu:** -| Id | Description | -| ------------------- | ------------------------------------------- | -| `formatStrong` | Set the font of the selected text to bold | -| `formatEmphasis` | Set the font of the selected text to italic | -| `formatUnderline` | Change the selected text to underline | -| `formatInlineCode` | Change the selected text to inline code | -| `formatStrike` | Strike through the selected text | -| `formatHyperlink` | Insert a hyperlink | -| `formatImage` | Insert a image | -| `formatClearFormat` | Clear the formatting of the selected text | +| Id | Default | Description | +| ------------------- | -------------------------------------------------- | ------------------------------------------- | +| `formatStrong` | CmdOrCtrl+B | Set the font of the selected text to bold | +| `formatEmphasis` | CmdOrCtrl+I | Set the font of the selected text to italic | +| `formatUnderline` | CmdOrCtrl+U | Change the selected text to underline | +| `formatInlineCode` | CmdOrCtrl+` | Change the selected text to inline code | +| `formatInlineMath` | CmdOrCtrl+Shift+M | Change the selected text to inline math | +| `formatStrike` | CmdOrCtrl+D | Strike through the selected text | +| `formatHyperlink` | CmdOrCtrl+L | Insert a hyperlink | +| `formatImage` | CmdOrCtrl+Shift+I | Insert a image | +| `formatClearFormat` | CmdOrCtrl+Shift+R | Clear the formatting of the selected text | **Window menu:** -| Id | Description | -| ------------------------ | ---------------------- | -| `windowMinimize` | Minimize the window | -| `windowToggleFullScreen` | Toggle fullscreen mode | +| Id | Default | Description | +| ---------------- | --------------------------------- | ------------------- | +| `windowMinimize` | CmdOrCtrl+M | Minimize the window | **View menu:** -| Id | Description | -| ----------------------------- | ---------------------------------------- | -| `viewSourceCodeMode` | Switch to source code mode | -| `viewTypewriterMode` | Enable typewriter mode | -| `viewFocusMode` | Enable focus mode | -| `viewToggleSideBar` | Toggle sidebar | -| `viewToggleTabBar` | Toggle tabbar | -| `viewDevToggleDeveloperTools` | Toggle developer tools (debug mode only) | -| `viewDevReload` | Reload window (debug mode only) | +| Id | Default | Description | +| ----------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------ | +| `viewToggleFullScreen` | F11 | Toggle fullscreen mode (or Ctrl+Command+F on macOS) | +| `viewSourceCodeMode` | CmdOrCtrl+Alt+S | Switch to source code mode | +| `viewTypewriterMode` | CmdOrCtrl+Alt+T | Enable typewriter mode | +| `viewFocusMode` | CmdOrCtrl+Shift+F | Enable focus mode | +| `viewToggleSideBar` | CmdOrCtrl+J | Toggle sidebar | +| `viewToggleTabBar` | CmdOrCtrl+Alt+B | Toggle tabbar | +| `viewDevToggleDeveloperTools` | CmdOrCtrl+Alt+I | Toggle developer tools (debug mode only) | +| `viewDevReload` | CmdOrCtrl+R | Reload window (debug mode only) | + +**Misc** + +| Id | Default | Description | +| ------------------- | ---------------------------------------------------- | ---------------------------- | +| `tabsCycleForward` | CmdOrCtrl+Tab | Cycle through tabs | +| `tabsCycleBackward` | CmdOrCtrl+Shift+Tab | Cycle backwards through tabs | +| `tabsSwitchToLeft` | CmdOrCtrl+PageUp | Switch tab to the left | +| `tabsSwitchToRight` | CmdOrCtrl+PageDown | Switch tab to the right | diff --git a/src/main/keyboard/shortcutHandler.js b/src/main/keyboard/shortcutHandler.js index 60ae3068..3a732ef3 100644 --- a/src/main/keyboard/shortcutHandler.js +++ b/src/main/keyboard/shortcutHandler.js @@ -21,11 +21,11 @@ class Keybindings { this.configPath = path.join(userDataPath, 'keybindings.json') this.keys = new Map([ - // marktext - macOS only + // Mark Text - macOS only ['mtHide', 'Command+H'], ['mtHideOthers', 'Command+Alt+H'], - // file menu + // File menu ['fileNewFile', 'CmdOrCtrl+N'], ['fileNewTab', 'CmdOrCtrl+Shift+T'], ['fileOpenFile', 'CmdOrCtrl+O'], @@ -38,7 +38,7 @@ class Keybindings { ['fileCloseWindow', 'CmdOrCtrl+Shift+W'], ['fileQuit', 'CmdOrCtrl+Q'], - // edit menu + // Edit menu ['editUndo', 'CmdOrCtrl+Z'], ['editRedo', 'CmdOrCtrl+Shift+Z'], ['editCut', 'CmdOrCtrl+X'], @@ -57,7 +57,7 @@ class Keybindings { ['editAidou', 'CmdOrCtrl+/'], ['editScreenshot', 'CmdOrCtrl+Alt+A'], - // paragraph menu + // Paragraph menu ['paragraphHeading1', 'CmdOrCtrl+1'], ['paragraphHeading2', 'CmdOrCtrl+2'], ['paragraphHeading3', 'CmdOrCtrl+3'], @@ -79,7 +79,7 @@ class Keybindings { ['paragraphHorizontalLine', 'CmdOrCtrl+Alt+-'], ['paragraphYAMLFrontMatter', 'CmdOrCtrl+Alt+Y'], - // format menu + // Format menu ['formatStrong', 'CmdOrCtrl+B'], ['formatEmphasis', 'CmdOrCtrl+I'], ['formatUnderline', 'CmdOrCtrl+U'], @@ -90,10 +90,10 @@ class Keybindings { ['formatImage', 'CmdOrCtrl+Shift+I'], ['formatClearFormat', 'Shift+CmdOrCtrl+R'], - // window menu + // Window menu ['windowMinimize', 'CmdOrCtrl+M'], - // view menu + // View menu ['viewToggleFullScreen', isOsx ? 'Ctrl+Command+F' : 'F11'], ['viewSourceCodeMode', 'CmdOrCtrl+Alt+S'], ['viewTypewriterMode', 'CmdOrCtrl+Alt+T'], @@ -101,7 +101,13 @@ class Keybindings { ['viewToggleSideBar', 'CmdOrCtrl+J'], ['viewToggleTabBar', 'CmdOrCtrl+Alt+B'], ['viewDevToggleDeveloperTools', 'CmdOrCtrl+Alt+I'], - ['viewDevReload', 'CmdOrCtrl+R'] + ['viewDevReload', 'CmdOrCtrl+R'], + + // Misc + ['tabsCycleForward', 'CmdOrCtrl+Tab'], + ['tabsCycleBackward', 'CmdOrCtrl+Shift+Tab'], + ['tabsSwitchToLeft', 'CmdOrCtrl+PageUp'], + ['tabsSwitchToRight', 'CmdOrCtrl+PageDown'] ]) // fix non-US keyboards diff --git a/src/main/menu/index.js b/src/main/menu/index.js index 151487aa..1b1e25cf 100644 --- a/src/main/menu/index.js +++ b/src/main/menu/index.js @@ -164,7 +164,7 @@ class AppMenu { } } - buildEditorMenu (createShortcutMap, recentUsedDocuments) { + buildEditorMenu (createShortcutMap, recentUsedDocuments = null) { if (!recentUsedDocuments) { recentUsedDocuments = this.getRecentlyUsedDocuments() } @@ -175,6 +175,7 @@ class AppMenu { let shortcutMap = null if (createShortcutMap) { shortcutMap = parseMenu(menuTemplate) + this._appendMiscShortcuts(shortcutMap) } return { @@ -282,6 +283,37 @@ class AppMenu { }) } + _appendMiscShortcuts = shortcutMap => { + shortcutMap.push({ + accelerator: this._keybindings.getAccelerator('tabsCycleForward'), + click: (menuItem, win) => { + win.webContents.send('mt::tabs-cycle-right') + }, + id: null + }) + shortcutMap.push({ + accelerator: this._keybindings.getAccelerator('tabsCycleBackward'), + click: (menuItem, win) => { + win.webContents.send('mt::tabs-cycle-left') + }, + id: null + }) + shortcutMap.push({ + accelerator: this._keybindings.getAccelerator('tabsSwitchToLeft'), + click: (menuItem, win) => { + win.webContents.send('mt::tabs-cycle-left') + }, + id: null + }) + shortcutMap.push({ + accelerator: this._keybindings.getAccelerator('tabsSwitchToRight'), + click: (menuItem, win) => { + win.webContents.send('mt::tabs-cycle-right') + }, + id: null + }) + } + _setApplicationMenu (menu) { if (isLinux && !menu) { // WORKAROUND for Electron#16521: We cannot hide the (application) menu on Linux. diff --git a/src/renderer/pages/app.vue b/src/renderer/pages/app.vue index 2fa7e8d2..5f3ab77c 100644 --- a/src/renderer/pages/app.vue +++ b/src/renderer/pages/app.vue @@ -140,6 +140,7 @@ export default { dispatch('LINTEN_FOR_SET_LINE_ENDING') dispatch('LISTEN_FOR_NEW_TAB') dispatch('LISTEN_FOR_CLOSE_TAB') + dispatch('LISTEN_FOR_TAB_CYCLE') dispatch('LINTEN_FOR_PRINT_SERVICE_CLEARUP') dispatch('LINTEN_FOR_EXPORT_SUCCESS') dispatch('LISTEN_FOR_FILE_CHANGE') diff --git a/src/renderer/store/editor.js b/src/renderer/store/editor.js index 6ae6a5af..778d4727 100644 --- a/src/renderer/store/editor.js +++ b/src/renderer/store/editor.js @@ -544,6 +544,15 @@ const actions = { }) }, + LISTEN_FOR_TAB_CYCLE ({ commit, state, dispatch }) { + ipcRenderer.on('mt::tabs-cycle-left', e => { + dispatch('CYCLE_TABS', false) + }) + ipcRenderer.on('mt::tabs-cycle-right', e => { + dispatch('CYCLE_TABS', true) + }) + }, + CLOSE_TAB ({ dispatch }, file) { const { isSaved } = file if (isSaved) { @@ -553,6 +562,36 @@ const actions = { } }, + // Direction is a boolean where false is left and true right. + CYCLE_TABS ({ commit, state }, direction) { + const { tabs, currentFile } = state + if (tabs.length <= 1) { + return + } + + const currentIndex = tabs.findIndex(t => t.id === currentFile.id) + if (currentIndex === -1) { + console.error('CYCLE_TABS: Cannot find current tab index.') + return + } + + let nextTabIndex = 0 + if (!direction) { + // Switch tab to the left. + nextTabIndex = currentIndex === 0 ? tabs.length - 1 : currentIndex - 1 + } else { + // Switch tab to the right. + nextTabIndex = (currentIndex + 1) % tabs.length + } + + const nextTab = tabs[nextTabIndex] + if (!nextTab || !nextTab.id) { + console.error(`CYCLE_TABS: Cannot find next tab (index="${nextTabIndex}").`) + return + } + commit('SET_CURRENT_FILE', nextTab) + }, + /** * Create a new untitled tab optional from a markdown string. *