From 6e1761a1f5d1506b09c8f366065e195ea7d32e3e Mon Sep 17 00:00:00 2001 From: Rieon Ke Date: Thu, 2 Jul 2020 15:21:19 +0800 Subject: [PATCH] impl tabc[lose] ex command --- resources/META-INF/includes/VimExCommands.xml | 1 + .../idea/vim/ex/handler/TabCloseHandler.kt | 157 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 src/com/maddyhome/idea/vim/ex/handler/TabCloseHandler.kt diff --git a/resources/META-INF/includes/VimExCommands.xml b/resources/META-INF/includes/VimExCommands.xml index 996f944f87..2472d35fe8 100644 --- a/resources/META-INF/includes/VimExCommands.xml +++ b/resources/META-INF/includes/VimExCommands.xml @@ -60,6 +60,7 @@ + diff --git a/src/com/maddyhome/idea/vim/ex/handler/TabCloseHandler.kt b/src/com/maddyhome/idea/vim/ex/handler/TabCloseHandler.kt new file mode 100644 index 0000000000..1b5265e749 --- /dev/null +++ b/src/com/maddyhome/idea/vim/ex/handler/TabCloseHandler.kt @@ -0,0 +1,157 @@ +/* + * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform + * Copyright (C) 2003-2020 The IdeaVim authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.maddyhome.idea.vim.ex.handler + +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx +import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.ex.CommandHandler +import com.maddyhome.idea.vim.ex.ExCommand +import com.maddyhome.idea.vim.ex.flags + +/** + * @author Rieon Ke + */ +class TabCloseHandler : CommandHandler.SingleExecution() { + + override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) + + override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean { + + val project = PlatformDataKeys.PROJECT.getData(context) ?: return false; + val fileEditorManager = FileEditorManagerEx.getInstanceEx(project); + val currentWindow = fileEditorManager.currentWindow + val tabbedPane = currentWindow.tabbedPane + + val current = tabbedPane.selectedIndex + val tabCount = tabbedPane.tabCount + + val argument = cmd.argument + val index = getTabIndexToClose(argument, current, tabCount - 1) + + if (index != null) { + val select = if (index == current) index + 1 else current + tabbedPane.removeTabAt(index, select) + } else { + VimPlugin.showMessage("Error: invalid command argument") + } + + return true + } + + /** + * parse command argument to tab index. + * :tabclose -2 close the two previous tab page + * :tabclose + close the next tab page + * :tabclose +2 close the two next tab page + * :tabclose 3 close the third tab page + * :tabclose $ close the last tab page + * @param arg command argument + * @param current current selected tab index + * @param last the last tab index of active tabbed pane + * @return tab index to close + */ + private fun getTabIndexToClose(arg: String, current: Int, last: Int): Int? { + + if (arg.isEmpty()) { + return current + } + + if (last < 0) { + return null + } + + val sb = StringBuilder() + var sign = Char.MIN_VALUE + var end = false + + for (c in arg) { + when { + c in '0'..'9' && !end -> { + sb.append(c) + } + + (c == '-' || c == '+') && !end && sb.isEmpty() && sign == Char.MIN_VALUE -> { + sign = c + } + + c == '$' && sb.isEmpty() && sign == Char.MIN_VALUE -> { + end = true + } + + c == ' ' -> { + //ignore + } + else -> return null + + } + } + + + val idxStr = sb.toString() + + val index = when { + end -> { + last + } + sb.isEmpty() -> { + when (sign) { + '+' -> { + current + 1 + } + '-' -> { + current - 1 + } + else -> { + current + } + } + } + else -> { + try { + val idx = Integer.valueOf(idxStr) + when (sign) { + '+' -> { + current + idx + } + + '-' -> { + current - idx + } + + else -> { + idx + } + + } + } catch (e: NumberFormatException) { + return null + } + } + } + if (index < 0) return 0 + if (index > last) return last + return index + + } + + +}