diff --git a/src/main/java/com/maddyhome/idea/vim/helper/EditorHelper.java b/src/main/java/com/maddyhome/idea/vim/helper/EditorHelper.java index b927bc902b..cf1a02cbdc 100644 --- a/src/main/java/com/maddyhome/idea/vim/helper/EditorHelper.java +++ b/src/main/java/com/maddyhome/idea/vim/helper/EditorHelper.java @@ -157,6 +157,19 @@ public static int getApproximateScreenWidth(final @NotNull Editor editor) { return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor)); } + /** + * Gets the number of characters that can be fit inside the output panel for an editor. + *

+ * This will be greater than the approximate screen width as it also includes any gutter components in the editor. + *

+ * + * @param editor The editor + * @return The approximate number of columns that can fit in the output panel + */ + public static int getApproximateOutputPanelWidth(final @NotNull Editor editor) { + return (int)(editor.getComponent().getWidth() / getPlainSpaceWidthFloat(editor)); + } + /** * Gets the width of the space character in the editor's plain font as a float. *

@@ -273,7 +286,7 @@ else if (bottomInlayHeight > visibleArea.height - caretScreenOffset + editor.get // Scroll the given visual line to the caret location, but do not scroll down passed the end of file, or the current // virtual space at the bottom of the screen - @NotNull final VimEditor editor1 = new IjVimEditor(editor); + final @NotNull VimEditor editor1 = new IjVimEditor(editor); final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1; final int yBottomLineOffset = max(getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine), visibleArea.y); scrollVertically(editor, min(yVisualLine - caretScreenOffset - inlayOffset, yBottomLineOffset)); @@ -325,7 +338,7 @@ public static void scrollVisualLineToMiddleOfScreen(@NotNull Editor editor, int final int lineHeight = editor.getLineHeight(); final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight); - @NotNull final VimEditor editor1 = new IjVimEditor(editor); + final @NotNull VimEditor editor1 = new IjVimEditor(editor); final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1; final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine); @@ -379,7 +392,7 @@ private static int getExEntryHeight() { return 0; } - private static int getHorizontalScrollbarHeight(@NotNull final Editor editor) { + private static int getHorizontalScrollbarHeight(final @NotNull Editor editor) { // Horizontal scrollbars on macOS are either transparent AND auto-hide, so we don't need to worry about obscured // text, or always visible, opaque and outside the content area, so we don't need to adjust for them // Transparent scrollbars on Windows and Linux are overlays on the editor content area, and always visible. That @@ -462,7 +475,7 @@ public static void scrollColumnToRightOfScreen(@NotNull Editor editor, int visua */ public static Pair scrollFullPageDown(final @NotNull Editor editor, int pages) { final Rectangle visibleArea = getVisibleArea(editor); - @NotNull final VimEditor editor2 = new IjVimEditor(editor); + final @NotNull VimEditor editor2 = new IjVimEditor(editor); final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor2) - 1; int y = visibleArea.y + visibleArea.height; @@ -480,7 +493,7 @@ public static Pair scrollFullPageDown(final @NotNull Editor ed caretVisualLine = lastVisualLine; } else { - @NotNull final VimEditor editor1 = new IjVimEditor(editor); + final @NotNull VimEditor editor1 = new IjVimEditor(editor); caretVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1; completed = false; } @@ -515,7 +528,7 @@ public static Pair scrollFullPageDown(final @NotNull Editor ed public static Pair scrollFullPageUp(final @NotNull Editor editor, int pages) { final Rectangle visibleArea = getVisibleArea(editor); final int lineHeight = editor.getLineHeight(); - @NotNull final VimEditor editor1 = new IjVimEditor(editor); + final @NotNull VimEditor editor1 = new IjVimEditor(editor); final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1; int y = visibleArea.y; diff --git a/src/main/java/com/maddyhome/idea/vim/helper/IjEditorHelper.kt b/src/main/java/com/maddyhome/idea/vim/helper/IjEditorHelper.kt index 08372c22b0..12d8618a22 100644 --- a/src/main/java/com/maddyhome/idea/vim/helper/IjEditorHelper.kt +++ b/src/main/java/com/maddyhome/idea/vim/helper/IjEditorHelper.kt @@ -13,7 +13,6 @@ import com.intellij.openapi.editor.ReadOnlyFragmentModificationException import com.intellij.openapi.editor.VisualPosition import com.intellij.openapi.editor.actionSystem.EditorActionManager import com.intellij.openapi.editor.ex.util.EditorUtil -import com.maddyhome.idea.vim.api.EngineEditorHelper import com.maddyhome.idea.vim.api.EngineEditorHelperBase import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.VimRangeMarker @@ -42,6 +41,10 @@ internal class IjEditorHelper : EngineEditorHelperBase() { return EditorHelper.getApproximateScreenWidth(editor.ij) } + override fun getApproximateOutputPanelWidth(editor: VimEditor): Int { + return EditorHelper.getApproximateOutputPanelWidth(editor.ij) + } + override fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: Exception) { return EditorActionManager.getInstance() .getReadonlyFragmentModificationHandler(editor.ij.document) diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/EngineEditorHelper.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/EngineEditorHelper.kt index 3bc926d4e8..2cd7f0ee49 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/EngineEditorHelper.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/EngineEditorHelper.kt @@ -18,7 +18,23 @@ interface EngineEditorHelper { fun amountOfInlaysBeforeVisualPosition(editor: VimEditor, pos: VimVisualPosition): Int fun getVisualLineAtTopOfScreen(editor: VimEditor): Int fun getVisualLineAtBottomOfScreen(editor: VimEditor): Int + + /** + * Return the approximate width, in columns, of the editor surface + * + * This is used for calculating the usable editor width, for editor features such as horizontal scrolling. + */ fun getApproximateScreenWidth(editor: VimEditor): Int + + /** + * Return the approximate width, in columns, of the output panel for a given editor + * + * This value is the approximate number of columns that can be displayed in the output panel for an editor. It will be + * greater than the value returned by [getApproximateScreenWidth], which is the number of editor columns in what Vim + * calls a "screen". That value does not include the space taken up by the editor gutter and other components, and if + * used for the output panel will leave a gap on the right-hand side of the panel. + */ + fun getApproximateOutputPanelWidth(editor: VimEditor): Int fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: java.lang.Exception) fun pad(editor: VimEditor, line: Int, to: Int): String fun inlayAwareOffsetToVisualPosition(editor: VimEditor, offset: Int): VimVisualPosition @@ -238,9 +254,7 @@ fun VimEditor.getText(range: TextRange): String { val end = range.endOffsets[i] val line = getText(start, end) if (line.isEmpty()) { - for (j in 0 until max) { - res.append(' ') - } + repeat(max) { res.append(' ') } } else { res.append(line) } @@ -307,4 +321,4 @@ interface VimRangeMarker { val isValid: Boolean fun dispose() -} \ No newline at end of file +} diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimDigraphGroupBase.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimDigraphGroupBase.kt index ada96f65d5..5203cda7c3 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimDigraphGroupBase.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimDigraphGroupBase.kt @@ -126,7 +126,7 @@ open class VimDigraphGroupBase() : VimDigraphGroup { } override fun showDigraphs(editor: VimEditor, showHeaders: Boolean) { - val width = injector.engineEditorHelper.getApproximateScreenWidth(editor).let { if (it < 10) 80 else it } + val width = injector.engineEditorHelper.getApproximateOutputPanelWidth(editor).let { if (it < 10) 80 else it } // Vim's columns are 13 characters wide, but for some reason, they suddenly switch to 12. It makes no obvious sense, // and it's a quirk too far to copy. diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/SetCommand.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/SetCommand.kt index ffba2d7245..e488779185 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/SetCommand.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/SetCommand.kt @@ -195,7 +195,7 @@ fun parseOptionLine(editor: VimEditor, context: ExecutionContext, args: String, } // Now show all options that were individually requested - if (toShow.size > 0) { + if (toShow.isNotEmpty()) { showOptions(editor, context, toShow, scope, false, columnFormat) } @@ -240,9 +240,7 @@ private fun showOptions( if (columnFormat || optionAsString.length >= colWidth) extra.add(optionAsString) else cells.add(optionAsString) } - // Note that this is the approximate width of the associated editor, not the ex output panel! - // It excludes gutter width, for example - val width = injector.engineEditorHelper.getApproximateScreenWidth(editor).let { if (it < 20) 80 else it } + val width = injector.engineEditorHelper.getApproximateOutputPanelWidth(editor).let { if (it < 20) 80 else it } val colCount = width / colWidth val height = ceil(cells.size.toDouble() / colCount.toDouble()).toInt() @@ -260,18 +258,14 @@ private fun showOptions( for (c in 0 until colCount) { val index = c * height + h if (index < cells.size) { - val padLength = lengthAtStartOfLine + (c * colWidth) - length - for (i in 1..padLength) { - append(' ') - } - + repeat(lengthAtStartOfLine + (c * colWidth) - length) { append(' ') } append(cells[index]) } } appendLine() } - // Add any lines that are too long to fit into columns. The panel will soft wrap text + // Add any lines that are too long to fit into columns. The panel will soft-wrap text for (option in extra) { appendLine(option) }