Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package pl.mareklangiewicz.kommand.vim
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.toList
import okio.Path
import pl.mareklangiewicz.annotations.DelicateApi
import pl.mareklangiewicz.annotations.NotPortableApi
import pl.mareklangiewicz.bad.chk
import pl.mareklangiewicz.kground.*
import pl.mareklangiewicz.kground.io.pth
import pl.mareklangiewicz.kommand.*
import pl.mareklangiewicz.kommand.vim.XVim.Option.*
import pl.mareklangiewicz.kommand.vim.XVim.Option.Companion.KeysScriptStdInForVim
import pl.mareklangiewicz.kommand.vim.XVim.Option.Companion.VimRcNONE
import pl.mareklangiewicz.udata.strf
/**
* When opening stdin content, vim expects commands from stderr.
*
* BTW: When launching vim from terminal, all (0, 1, 2) streams are connected to the same tty device by default,
* so in that case, it's great default behavior, that vim tries to use stderr as input when stdin is used for content.
*/
@DelicateApi("When opening stdin content, vim expects commands from (redirected) stderr!")
fun vimStdIn(init: XVim.() -> Unit = {}): XVim = vim("-".pth, init = init)
fun gvimStdIn(init: XVim.() -> Unit = {}): XVim = gvim("-".pth, init = init)
fun nvimStdIn(init: XVim.() -> Unit = {}): XVim = nvim("-".pth, init = init)
fun nvimMan(manpage: String, section: ManSection? = null): XVim = nvim {
val cmd = section?.number?.let { "hid Man $it $manpage" } ?: "hid Man $manpage"
-ExCmd(cmd)
}
/** GVim can display 'reading from stdin...' until it reads full [inLineS] flow and only then show the full content */
fun gvimLineS(inLineS: Flow, init: XVim.() -> Unit = {}) = ReducedScript {
gvimStdIn(init).ax(inLineS = inLineS)
}
fun gvimLines(inLines: List, init: XVim.() -> Unit = {}) = gvimLineS(inLines.asFlow(), init)
fun gvimContent(inContent: String, init: XVim.() -> Unit = {}) = gvimLines(inContent.lines(), init)
fun vim(vararg files: Path, init: XVim.() -> Unit = {}) = XVim(XVim.Type.Vim, files.toMutableList()).apply(init)
fun nvim(vararg files: Path, init: XVim.() -> Unit = {}) = XVim(XVim.Type.NVim, files.toMutableList()).apply(init)
fun gvim(vararg files: Path, init: XVim.() -> Unit = {}) = XVim(XVim.Type.GVim, files.toMutableList()).apply(init)
// TODO NOW: nvim, opening specific lines, opening in existing editor (is servername same as in vim?),
// combine with Ide as in kolib openInIdeOrGVim but better selecting (with nvim too)
/**
* Useful for playing with ex-mode interactively before writing script for one of:
* [vimExScriptStdIn] or [vimExScriptContent] or [vimExScriptFile]
* Note: there is :vi (:visual) command available to switch to normal (visual) mode.
*/
fun vimEx(vararg files: Path, init: XVim.() -> Unit = {}): XVim = vim(*files) { -ExMode; init() }
/**
* Useful for playing with ex-mode interactively before writing script for one of:
* [vimExScriptStdIn] or [vimExScriptContent] or [vimExScriptFile]
* This "Improved" flavor differs mostly (only??) in interactive features, so it's nicer,
* but still can be useful playground before creating ex-mode script.
* Note: there is :vi (:visual) command available to switch to normal (visual) mode.
*/
fun vimExIm(vararg files: Path, init: XVim.() -> Unit = {}): XVim = vim(*files) { -ExImMode; init() }
fun vimExScriptStdIn(
vararg files: Path,
isViCompat: Boolean = false,
isCleanMode: Boolean = true,
): XVim = vim(*files) {
-ViCompat(isViCompat) // setting explicitly in scripts (not rely on .vimrc presence). BTW nvim is always nocompatible
if (isCleanMode) -CleanMode
-ExScriptMode // BTW initialization should be skipped in this mode
}
/**
* Normally should not be needed, but in case of problems it can be useful to experiment with these settings
* Proposed settings are inspired by answers/flags from SO (which can be incorrect or redundant):
* https://stackoverflow.com/questions/18860020/executing-vim-commands-in-a-shell-script
*/
@OptIn(NotPortableApi::class)
fun vimExScriptStdInWithExplicitSettings(
vararg files: Path,
isViCompat: Boolean = false,
isDebugMode: Boolean = false,
isCleanMode: Boolean = true,
isNoPluginMode: Boolean = false,
isVimRcNONE: Boolean = true,
isSwapNONE: Boolean = false, // in nvim swap is disabled in ExScriptMode anyway (not sure about original vim)
isSetNoMore: Boolean = false, // I guess it shouldn't be needed because ExScriptMode is not TUI, but I'm not sure.
isTermDumb: Boolean = false, // I guess it shouldn't be needed because ExScriptMode is not TUI, but I'm not sure.
): XVim = vim(*files) {
-ViCompat(isViCompat) // setting explicitly in scripts (not rely on .vimrc presence). BTW nvim is always nocompatible
if (isDebugMode) -DebugMode
if (isCleanMode) -CleanMode
if (isNoPluginMode) -NoPluginMode
if (isVimRcNONE) -VimRcNONE // although initialization should be skipped anyway in ExScriptMode
if (isSwapNONE) -SwapNONE
if (isSetNoMore) -ExCmd("set nomore") // avoids blocking/pausing when some output/listing fills whole screen
if (isTermDumb) -TermName("dumb") // BTW nvim does not support it
-ExScriptMode
}
fun vimExScriptContent(
exScriptContent: String,
vararg files: Path,
isViCompat: Boolean = false,
isCleanMode: Boolean = true,
): ReducedKommand> = vimExScriptStdIn(files = files, isViCompat = isViCompat, isCleanMode = isCleanMode)
.reducedManually {
stdin.collect(exScriptContent.lineSequence().asFlow())
val out = stdout.toList() // ex-commands can print stuff (like :list, :number, :print, :set, also see :verbose)
awaitAndChkExit(firstCollectErr = true)
out
}
/**
* This version uses [XVim.Option.Session] for [exScriptFile].
* @param exScriptFile can not start with "-" (or be empty).
*/
fun vimExScriptFile(
exScriptFile: String = "Session.vim",
vararg files: Path,
isViCompat: Boolean = false,
isCleanMode: Boolean = true,
): XVim = vim(*files) {
-ViCompat(isViCompat) // setting explicitly in scripts (not rely on .vimrc presence). BTW nvim is always nocompatible
if (isCleanMode) -CleanMode
-ExScriptMode // still needed (even though Session below) because we want silent mode prepared for usage without TTY
-Session(exScriptFile)
} // BTW ex-commands can print stuff (like :list, :number, :print, :set, also see :verbose)
@OptIn(NotPortableApi::class)
fun vimKeysScriptFile(
keysScriptFile: Path,
vararg files: Path,
isViCompat: Boolean = false,
isCleanMode: Boolean = true,
isSwapNONE: Boolean = true,
isSetNoMore: Boolean = true,
isTermDumb: Boolean = true,
): XVim = vim(*files) {
-ViCompat(isViCompat) // setting explicitly in scripts (not rely on .vimrc presence). BTW nvim is always nocompatible
if (isCleanMode) -CleanMode
if (isSwapNONE) -SwapNONE
if (isSetNoMore) -ExCmd("set nomore") // avoids blocking/pausing when some output/listing fills whole screen
if (isTermDumb) -TermName("dumb") // BTW nvim does not support it
-KeysScriptIn(keysScriptFile)
} // BTW stdout should not be used as vim will unfortunately print screen content there
/**
* Note: current impl adds \n at the end of the keys script.
* It's because internal details of [StdinCollector.collect], [Kommand.ax], etc..
* generally KommandLine currently treats input as flow of lines.
*/
@OptIn(NotPortableApi::class, DelicateApi::class)
fun vimKeysScriptStdIn(
vararg files: Path,
isViCompat: Boolean = false,
isCleanMode: Boolean = true,
isSwapNONE: Boolean = true,
isSetNoMore: Boolean = true,
isTermDumb: Boolean = true,
): XVim = vim(*files) {
-ViCompat(isViCompat) // setting explicitly in scripts (not rely on .vimrc presence). BTW nvim is always nocompatible
if (isCleanMode) -CleanMode
if (isSwapNONE) -SwapNONE
if (isSetNoMore) -ExCmd("set nomore") // avoids blocking/pausing when some output/listing fills whole screen
if (isTermDumb) -TermName("dumb") // BTW nvim does not support it
-KeysScriptStdInForVim // BTW waiting for answer if it's a good approach: https://github.com/vim/vim/discussions/15315
} // BTW stdout should not be used as vim will unfortunately print screen content there
/**
* Note: current impl adds \n at the end of the [keysScriptContent].
* It's because internal details of [StdinCollector.collect], [Kommand.ax], etc..
* generally KommandLine currently treats input as flow of lines.
*/
@OptIn(NotPortableApi::class, DelicateApi::class)
fun vimKeysScriptContent(
keysScriptContent: String,
vararg files: Path,
isViCompat: Boolean = false,
isCleanMode: Boolean = true,
isSwapNONE: Boolean = true,
isSetNoMore: Boolean = true,
isTermDumb: Boolean = true,
): ReducedKommand = vimKeysScriptStdIn(
files = files,
isViCompat = isViCompat,
isCleanMode = isCleanMode,
isSwapNONE = isSwapNONE,
isSetNoMore = isSetNoMore,
isTermDumb = isTermDumb,
).reducedManually {
stdin.collect(keysScriptContent.lineSequence().asFlow())
awaitAndChkExit(firstCollectErr = true)
}
// Note: I could add all script flavored wrappers here for nvim as well, but let's not do it.
// Vim is more portable (github actions etc), and user can wrap nvim himself if needed.
@Suppress("unused")
data class XVim(
val type: Type = Type.Vim,
val files: MutableList = mutableListOf(),
val options: MutableList