mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-05-30 13:34:08 +02:00
151 lines
5.1 KiB
Kotlin
151 lines
5.1 KiB
Kotlin
/*
|
|
* Copyright 2003-2023 The IdeaVim authors
|
|
*
|
|
* Use of this source code is governed by an MIT-style
|
|
* license that can be found in the LICENSE.txt file or at
|
|
* https://opensource.org/licenses/MIT.
|
|
*/
|
|
|
|
package com.maddyhome.idea.vim.ui
|
|
|
|
import com.intellij.openapi.editor.Editor
|
|
import com.intellij.openapi.fileEditor.FileEditorManagerListener
|
|
import com.intellij.openapi.project.Project
|
|
import com.intellij.openapi.project.ProjectManager
|
|
import com.intellij.openapi.util.NlsSafe
|
|
import com.intellij.openapi.wm.StatusBar
|
|
import com.intellij.openapi.wm.StatusBarWidget
|
|
import com.intellij.openapi.wm.StatusBarWidgetFactory
|
|
import com.intellij.openapi.wm.WindowManager
|
|
import com.intellij.openapi.wm.impl.status.EditorBasedWidget
|
|
import com.intellij.util.Consumer
|
|
import com.maddyhome.idea.vim.KeyHandler
|
|
import com.maddyhome.idea.vim.VimPlugin
|
|
import com.maddyhome.idea.vim.api.VimEditor
|
|
import com.maddyhome.idea.vim.api.globalOptions
|
|
import com.maddyhome.idea.vim.api.injector
|
|
import com.maddyhome.idea.vim.common.EditorListener
|
|
import com.maddyhome.idea.vim.helper.EngineStringHelper
|
|
import com.maddyhome.idea.vim.helper.VimNlsSafe
|
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
|
import com.maddyhome.idea.vim.newapi.ij
|
|
import com.maddyhome.idea.vim.newapi.vim
|
|
import com.maddyhome.idea.vim.options.GlobalOptionChangeListener
|
|
import org.jetbrains.annotations.NonNls
|
|
import java.awt.Component
|
|
import java.awt.event.MouseEvent
|
|
|
|
internal object ShowCmd {
|
|
// https://github.com/vim/vim/blob/b376ace1aeaa7614debc725487d75c8f756dd773/src/vim.h#L1721
|
|
private const val SHOWCMD_COLS = 10
|
|
|
|
@NonNls
|
|
internal const val ID = "IdeaVimShowCmd"
|
|
|
|
@NlsSafe
|
|
internal const val displayName = "IdeaVim showcmd"
|
|
|
|
fun update() {
|
|
val windowManager = WindowManager.getInstance()
|
|
ProjectManager.getInstance().openProjects.forEach {
|
|
val statusBar = windowManager.getStatusBar(it)
|
|
statusBar.updateWidget(ID)
|
|
}
|
|
}
|
|
|
|
fun getWidgetText(editor: Editor?): String {
|
|
// Vim only shows the last 10 characters. See normal.c:add_to_showcmd
|
|
// https://github.com/vim/vim/blob/b376ace1aeaa7614debc725487d75c8f756dd773/src/normal.c#L1885-L1890
|
|
return getFullText(editor).takeLast(SHOWCMD_COLS)
|
|
}
|
|
|
|
fun getFullText(editor: Editor?): String {
|
|
if (!injector.globalOptions().showcmd || editor == null || editor.isDisposed) return ""
|
|
|
|
val keyState = KeyHandler.getInstance().keyHandlerState
|
|
return EngineStringHelper.toPrintableCharacters(keyState.commandBuilder.keys + keyState.mappingState.keys)
|
|
}
|
|
}
|
|
|
|
internal object ShowCmdOptionChangeListener : GlobalOptionChangeListener {
|
|
override fun onGlobalOptionChanged() {
|
|
ShowCmd.update()
|
|
}
|
|
}
|
|
|
|
internal class ShowCmdStatusBarWidgetFactory : StatusBarWidgetFactory/*, LightEditCompatible*/ {
|
|
override fun getId() = ShowCmd.ID
|
|
|
|
override fun getDisplayName(): String = ShowCmd.displayName
|
|
|
|
override fun disposeWidget(widget: StatusBarWidget) {
|
|
// Nothing
|
|
}
|
|
|
|
override fun isAvailable(project: Project): Boolean {
|
|
VimPlugin.getInstance()
|
|
return injector.globalOptions().showcmd
|
|
}
|
|
|
|
override fun createWidget(project: Project): StatusBarWidget = Widget(project)
|
|
|
|
override fun canBeEnabledOn(statusBar: StatusBar): Boolean = true
|
|
|
|
// Should be configured via `set showcmd`
|
|
override fun isConfigurable(): Boolean = false
|
|
}
|
|
|
|
// `:help 'showcmd'`
|
|
// Widget shows:
|
|
// * Partial command, as it's being typed
|
|
// * When selecting characters within a line, the number of characters
|
|
// * Tabs are shown as one char
|
|
// * If the number of bytes is different, this is also shown: "2-6"
|
|
// * When selecting more than one line, the number of lines
|
|
// * When selecting a block, the size in screen characters: {lines}x{columns}
|
|
//
|
|
// We only need to show partial commands, since the standard PositionPanel shows the other information already, with
|
|
// the exception of "{lines}x{columns}" (it shows "x carets" instead)
|
|
internal class Widget(project: Project) :
|
|
EditorBasedWidget(project),
|
|
StatusBarWidget.Multiframe,
|
|
StatusBarWidget.TextPresentation,
|
|
FileEditorManagerListener {
|
|
|
|
override fun ID() = ShowCmd.ID
|
|
|
|
override fun getPresentation(): StatusBarWidget.WidgetPresentation = this
|
|
|
|
override fun getClickConsumer(): Consumer<MouseEvent>? = null
|
|
|
|
@VimNlsSafe
|
|
override fun getTooltipText(): String {
|
|
var count = ShowCmd.getFullText(getEditor())
|
|
if (count.isNotBlank()) count = ": $count"
|
|
return "${ShowCmd.displayName}$count"
|
|
}
|
|
|
|
override fun getText(): String = ShowCmd.getWidgetText(getEditor())
|
|
|
|
override fun getAlignment() = Component.CENTER_ALIGNMENT
|
|
|
|
// Multiframe#copy to show the widget on popped out editors
|
|
override fun copy(): StatusBarWidget = Widget(project)
|
|
}
|
|
|
|
internal class ShowCmdWidgetUpdater : EditorListener {
|
|
override fun focusGained(editor: VimEditor) {
|
|
editor.ij.project?.let { selectionChanged(it) }
|
|
}
|
|
|
|
override fun focusLost(editor: VimEditor) {
|
|
editor.ij.project?.let { selectionChanged(it) }
|
|
}
|
|
|
|
private fun selectionChanged(project: Project) {
|
|
val windowManager = WindowManager.getInstance()
|
|
val statusBar = windowManager.getStatusBar(project)
|
|
statusBar.updateWidget(ShowCmd.ID)
|
|
}
|
|
}
|