More features added. License file added.
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||||
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
|
# Released under the terms of the WTFPL license https://www.wtfpl.net/
|
||||||
|
|
||||||
|
# Bim was partially created with bim
|
||||||
|
# Does that make it a recursive text editor?
|
||||||
|
|
||||||
|
# Behold! Vim in bash. Has anyone else ever created something so diabolically evil?
|
||||||
|
|
||||||
filePath="${1:-}"
|
filePath="${1:-}"
|
||||||
mode="command"
|
mode="command"
|
||||||
statusMessage=""
|
statusMessage=""
|
||||||
@@ -8,7 +15,11 @@ renderedMessage=$'\001'
|
|||||||
pendingInput=""
|
pendingInput=""
|
||||||
pendingCommand=""
|
pendingCommand=""
|
||||||
commandCount=""
|
commandCount=""
|
||||||
|
lastChangeKeys=""
|
||||||
|
insertChangeKeys=""
|
||||||
|
replayKeysRemaining=0
|
||||||
hasYank=0
|
hasYank=0
|
||||||
|
yankType="line"
|
||||||
dirty=0
|
dirty=0
|
||||||
cursorRow=0
|
cursorRow=0
|
||||||
cursorCol=0
|
cursorCol=0
|
||||||
@@ -85,9 +96,14 @@ file_info() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw_message() {
|
draw_message() {
|
||||||
if [[ "$statusMessage" != "$renderedMessage" ]]; then
|
local message="$statusMessage"
|
||||||
printf '\033[%s;1H%-*.*s' "$screenRows" "$screenCols" "$screenCols" "$statusMessage"
|
if [[ -n "$pendingCommand" || -n "$commandCount" ]]; then
|
||||||
renderedMessage="$statusMessage"
|
message="${commandCount}${pendingCommand}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$message" != "$renderedMessage" ]]; then
|
||||||
|
printf '\033[%s;1H%-*.*s' "$screenRows" "$screenCols" "$screenCols" "$message"
|
||||||
|
renderedMessage="$message"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +125,9 @@ draw_screen() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
draw_message
|
draw_message
|
||||||
|
if [[ "$mode" == "command" ]] && ((${#lines[cursorRow]} > 0 && cursorCol >= ${#lines[cursorRow]})); then
|
||||||
|
cursorCol=$(( ${#lines[cursorRow]} - 1 ))
|
||||||
|
fi
|
||||||
printf '\033[%s;%sH' "$((cursorRow - topRow + 1))" "$((cursorCol + 1))"
|
printf '\033[%s;%sH' "$((cursorRow - topRow + 1))" "$((cursorCol + 1))"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +136,7 @@ read_key() {
|
|||||||
if [[ -n "$pendingInput" ]]; then
|
if [[ -n "$pendingInput" ]]; then
|
||||||
key="${pendingInput:0:1}"
|
key="${pendingInput:0:1}"
|
||||||
pendingInput="${pendingInput:1}"
|
pendingInput="${pendingInput:1}"
|
||||||
|
((replayKeysRemaining > 0)) && ((replayKeysRemaining--))
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -340,6 +360,53 @@ move_word_end_forward() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
move_word_end_backward() {
|
||||||
|
local count="$1"
|
||||||
|
local i row col char
|
||||||
|
for ((i = 0; i < count; i++)); do
|
||||||
|
row="$cursorRow"
|
||||||
|
col="$cursorCol"
|
||||||
|
if ((row == 0 && col == 0)); then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
step_position_backward row col
|
||||||
|
|
||||||
|
while ((row > 0 || col > 0)); do
|
||||||
|
if ((col >= ${#lines[row]})); then
|
||||||
|
step_position_backward row col
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
char="${lines[row]:col:1}"
|
||||||
|
! is_blank_char "$char" && break
|
||||||
|
step_position_backward row col
|
||||||
|
done
|
||||||
|
|
||||||
|
cursorRow="$row"
|
||||||
|
cursorCol="$col"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
move_to_first_nonblank() {
|
||||||
|
local line="${lines[cursorRow]}"
|
||||||
|
local col=0
|
||||||
|
while ((col < ${#line})); do
|
||||||
|
if ! is_blank_char "${line:col:1}"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
((col++))
|
||||||
|
done
|
||||||
|
cursorCol="$col"
|
||||||
|
}
|
||||||
|
|
||||||
|
move_to_line() {
|
||||||
|
local lineNumber="$1"
|
||||||
|
((lineNumber < 1)) && lineNumber=1
|
||||||
|
((lineNumber > ${#lines[@]})) && lineNumber="${#lines[@]}"
|
||||||
|
cursorRow=$((lineNumber - 1))
|
||||||
|
clamp_cursor
|
||||||
|
}
|
||||||
|
|
||||||
command_count() {
|
command_count() {
|
||||||
if [[ -n "$commandCount" ]]; then
|
if [[ -n "$commandCount" ]]; then
|
||||||
printf '%s' "$commandCount"
|
printf '%s' "$commandCount"
|
||||||
@@ -348,6 +415,44 @@ command_count() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record_last_change() {
|
||||||
|
local keys="$1"
|
||||||
|
if ((replayKeysRemaining == 0)); then
|
||||||
|
lastChangeKeys="$keys"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
start_insert_change() {
|
||||||
|
local keys="$1"
|
||||||
|
if ((replayKeysRemaining == 0)); then
|
||||||
|
insertChangeKeys="$keys"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_insert_change() {
|
||||||
|
if ((replayKeysRemaining == 0 && ${#insertChangeKeys} > 0)); then
|
||||||
|
lastChangeKeys="${insertChangeKeys}"$'\033'
|
||||||
|
fi
|
||||||
|
insertChangeKeys=""
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat_last_change() {
|
||||||
|
local count="$1"
|
||||||
|
local repeatedKeys=""
|
||||||
|
local i
|
||||||
|
if [[ -z "$lastChangeKeys" ]]; then
|
||||||
|
statusMessage="No change to repeat"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
for ((i = 0; i < count; i++)); do
|
||||||
|
repeatedKeys+="$lastChangeKeys"
|
||||||
|
done
|
||||||
|
pendingInput="${repeatedKeys}${pendingInput}"
|
||||||
|
replayKeysRemaining=$((replayKeysRemaining + ${#repeatedKeys}))
|
||||||
|
statusMessage=""
|
||||||
|
}
|
||||||
|
|
||||||
save_undo() {
|
save_undo() {
|
||||||
undoLines=("${lines[@]}")
|
undoLines=("${lines[@]}")
|
||||||
undoCursorRow="$cursorRow"
|
undoCursorRow="$cursorRow"
|
||||||
@@ -491,6 +596,43 @@ delete_range() {
|
|||||||
clamp_cursor
|
clamp_cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line_end_for_operator() {
|
||||||
|
local row="$1"
|
||||||
|
printf '%s' "${#lines[row]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
yank_range() {
|
||||||
|
local startRow="$1"
|
||||||
|
local startCol="$2"
|
||||||
|
local endRow="$3"
|
||||||
|
local endCol="$4"
|
||||||
|
local comparison row
|
||||||
|
|
||||||
|
comparison="$(compare_positions "$startRow" "$startCol" "$endRow" "$endCol")"
|
||||||
|
if [[ "$comparison" == "0" ]]; then
|
||||||
|
return 1
|
||||||
|
elif [[ "$comparison" == "1" ]]; then
|
||||||
|
local tempRow="$startRow"
|
||||||
|
local tempCol="$startCol"
|
||||||
|
startRow="$endRow"
|
||||||
|
startCol="$endCol"
|
||||||
|
endRow="$tempRow"
|
||||||
|
endCol="$tempCol"
|
||||||
|
fi
|
||||||
|
|
||||||
|
yankType="char"
|
||||||
|
if ((startRow == endRow)); then
|
||||||
|
yankBuffer=("${lines[startRow]:startCol:endCol-startCol}")
|
||||||
|
else
|
||||||
|
yankBuffer=("${lines[startRow]:startCol}")
|
||||||
|
for ((row = startRow + 1; row < endRow; row++)); do
|
||||||
|
yankBuffer+=("${lines[row]}")
|
||||||
|
done
|
||||||
|
yankBuffer+=("${lines[endRow]:0:endCol}")
|
||||||
|
fi
|
||||||
|
hasYank=1
|
||||||
|
}
|
||||||
|
|
||||||
delete_to_end_of_line() {
|
delete_to_end_of_line() {
|
||||||
local startRow="$cursorRow"
|
local startRow="$cursorRow"
|
||||||
local startCol="$cursorCol"
|
local startCol="$cursorCol"
|
||||||
@@ -509,6 +651,7 @@ delete_word_forward() {
|
|||||||
local startCol="$cursorCol"
|
local startCol="$cursorCol"
|
||||||
save_undo
|
save_undo
|
||||||
move_word_forward "$count"
|
move_word_forward "$count"
|
||||||
|
yank_range "$startRow" "$startCol" "$cursorRow" "$cursorCol"
|
||||||
delete_range "$startRow" "$startCol" "$cursorRow" "$cursorCol"
|
delete_range "$startRow" "$startCol" "$cursorRow" "$cursorCol"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,9 +661,50 @@ delete_word_backward() {
|
|||||||
local startCol="$cursorCol"
|
local startCol="$cursorCol"
|
||||||
save_undo
|
save_undo
|
||||||
move_word_backward "$count"
|
move_word_backward "$count"
|
||||||
|
yank_range "$startRow" "$startCol" "$cursorRow" "$cursorCol"
|
||||||
delete_range "$startRow" "$startCol" "$cursorRow" "$cursorCol"
|
delete_range "$startRow" "$startCol" "$cursorRow" "$cursorCol"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yank_word_forward() {
|
||||||
|
local count="$1"
|
||||||
|
local startRow="$cursorRow"
|
||||||
|
local startCol="$cursorCol"
|
||||||
|
move_word_forward "$count"
|
||||||
|
if yank_range "$startRow" "$startCol" "$cursorRow" "$cursorCol"; then
|
||||||
|
statusMessage="text yanked"
|
||||||
|
else
|
||||||
|
statusMessage="Nothing to yank"
|
||||||
|
fi
|
||||||
|
cursorRow="$startRow"
|
||||||
|
cursorCol="$startCol"
|
||||||
|
}
|
||||||
|
|
||||||
|
yank_word_backward() {
|
||||||
|
local count="$1"
|
||||||
|
local startRow="$cursorRow"
|
||||||
|
local startCol="$cursorCol"
|
||||||
|
move_word_backward "$count"
|
||||||
|
if yank_range "$startRow" "$startCol" "$cursorRow" "$cursorCol"; then
|
||||||
|
statusMessage="text yanked"
|
||||||
|
else
|
||||||
|
statusMessage="Nothing to yank"
|
||||||
|
fi
|
||||||
|
cursorRow="$startRow"
|
||||||
|
cursorCol="$startCol"
|
||||||
|
}
|
||||||
|
|
||||||
|
yank_to_end_of_line() {
|
||||||
|
local startRow="$cursorRow"
|
||||||
|
local startCol="$cursorCol"
|
||||||
|
local endCol
|
||||||
|
endCol="$(line_end_for_operator "$startRow")"
|
||||||
|
if yank_range "$startRow" "$startCol" "$startRow" "$endCol"; then
|
||||||
|
statusMessage="text yanked"
|
||||||
|
else
|
||||||
|
statusMessage="Nothing to yank"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
change_word() {
|
change_word() {
|
||||||
local count="$1"
|
local count="$1"
|
||||||
local startRow="$cursorRow"
|
local startRow="$cursorRow"
|
||||||
@@ -595,6 +779,150 @@ replace_chars() {
|
|||||||
statusMessage=""
|
statusMessage=""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
join_lines() {
|
||||||
|
local count="$1"
|
||||||
|
local i nextLine
|
||||||
|
if ((cursorRow + 1 >= ${#lines[@]})); then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
save_undo
|
||||||
|
for ((i = 0; i < count && cursorRow + 1 < ${#lines[@]}; i++)); do
|
||||||
|
nextLine="${lines[cursorRow+1]}"
|
||||||
|
lines[cursorRow]="${lines[cursorRow]} ${nextLine#"${nextLine%%[![:space:]]*}"}"
|
||||||
|
lines=("${lines[@]:0:cursorRow+1}" "${lines[@]:cursorRow+2}")
|
||||||
|
done
|
||||||
|
dirty=1
|
||||||
|
statusMessage=""
|
||||||
|
}
|
||||||
|
|
||||||
|
search_from_position() {
|
||||||
|
local pattern="$1"
|
||||||
|
local direction="$2"
|
||||||
|
local startRow="$3"
|
||||||
|
local startCol="$4"
|
||||||
|
local offset row col line searchPart matchPrefix
|
||||||
|
|
||||||
|
if [[ -z "$pattern" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for ((offset = 0; offset < ${#lines[@]}; offset++)); do
|
||||||
|
if [[ "$direction" == "forward" ]]; then
|
||||||
|
row=$(( (startRow + offset) % ${#lines[@]} ))
|
||||||
|
col=0
|
||||||
|
((offset == 0)) && col="$startCol"
|
||||||
|
else
|
||||||
|
row=$(( (startRow - offset + ${#lines[@]}) % ${#lines[@]} ))
|
||||||
|
col="${#lines[row]}"
|
||||||
|
((offset == 0)) && col="$startCol"
|
||||||
|
fi
|
||||||
|
|
||||||
|
line="${lines[row]}"
|
||||||
|
if [[ "$direction" == "forward" ]]; then
|
||||||
|
((col < 0)) && col=0
|
||||||
|
((col > ${#line})) && col="${#line}"
|
||||||
|
searchPart="${line:col}"
|
||||||
|
if [[ "$searchPart" == *"$pattern"* ]]; then
|
||||||
|
matchPrefix="${searchPart%%"$pattern"*}"
|
||||||
|
cursorRow="$row"
|
||||||
|
cursorCol=$((col + ${#matchPrefix}))
|
||||||
|
((offset > 0 && row <= startRow)) && statusMessage="search wrapped"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
((col < 0)) && col=0
|
||||||
|
((col > ${#line})) && col="${#line}"
|
||||||
|
searchPart="${line:0:col}"
|
||||||
|
if [[ "$searchPart" == *"$pattern"* ]]; then
|
||||||
|
matchPrefix="${searchPart%"$pattern"*}"
|
||||||
|
cursorRow="$row"
|
||||||
|
cursorCol="${#matchPrefix}"
|
||||||
|
((offset > 0 && row >= startRow)) && statusMessage="search wrapped"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSearchPattern=""
|
||||||
|
lastSearchDirection="forward"
|
||||||
|
|
||||||
|
run_search() {
|
||||||
|
local pattern="$1"
|
||||||
|
local direction="$2"
|
||||||
|
local startRow="$cursorRow"
|
||||||
|
local startCol="$cursorCol"
|
||||||
|
|
||||||
|
if [[ "$direction" == "forward" ]]; then
|
||||||
|
((startCol++))
|
||||||
|
else
|
||||||
|
((startCol--))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if search_from_position "$pattern" "$direction" "$startRow" "$startCol"; then
|
||||||
|
lastSearchPattern="$pattern"
|
||||||
|
lastSearchDirection="$direction"
|
||||||
|
[[ "$statusMessage" == "search wrapped" ]] || statusMessage=""
|
||||||
|
clamp_cursor
|
||||||
|
else
|
||||||
|
statusMessage="Pattern not found: $pattern"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat_search() {
|
||||||
|
local direction="$1"
|
||||||
|
if [[ -z "$lastSearchPattern" ]]; then
|
||||||
|
statusMessage="No previous search"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
run_search "$lastSearchPattern" "$direction"
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_search() {
|
||||||
|
local direction="$1"
|
||||||
|
local prompt key pattern
|
||||||
|
if [[ "$direction" == "forward" ]]; then
|
||||||
|
prompt="/"
|
||||||
|
else
|
||||||
|
prompt="?"
|
||||||
|
fi
|
||||||
|
pattern="$prompt"
|
||||||
|
while true; do
|
||||||
|
statusMessage="$pattern"
|
||||||
|
draw_screen
|
||||||
|
read_key || return
|
||||||
|
case "$key" in
|
||||||
|
$'\033')
|
||||||
|
statusMessage=""
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
$'\r'|$'\n')
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
$'\177'|$'\b')
|
||||||
|
if ((${#pattern} > 1)); then
|
||||||
|
pattern="${pattern:0:${#pattern}-1}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ "$key" =~ [[:print:]] ]]; then
|
||||||
|
pattern+="$key"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
pattern="${pattern#"$prompt"}"
|
||||||
|
if [[ -z "$pattern" ]]; then
|
||||||
|
statusMessage="Empty search"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
run_search "$pattern" "$direction"
|
||||||
|
}
|
||||||
|
|
||||||
open_line_below() {
|
open_line_below() {
|
||||||
lines=("${lines[@]:0:cursorRow+1}" "" "${lines[@]:cursorRow+1}")
|
lines=("${lines[@]:0:cursorRow+1}" "" "${lines[@]:cursorRow+1}")
|
||||||
((cursorRow++))
|
((cursorRow++))
|
||||||
@@ -617,6 +945,7 @@ yank_lines() {
|
|||||||
((actual > available)) && actual="$available"
|
((actual > available)) && actual="$available"
|
||||||
((actual < 1)) && actual=1
|
((actual < 1)) && actual=1
|
||||||
|
|
||||||
|
yankType="line"
|
||||||
yankBuffer=("${lines[@]:cursorRow:actual}")
|
yankBuffer=("${lines[@]:cursorRow:actual}")
|
||||||
hasYank=1
|
hasYank=1
|
||||||
statusMessage="$actual line yanked"
|
statusMessage="$actual line yanked"
|
||||||
@@ -631,6 +960,7 @@ delete_lines() {
|
|||||||
((actual < 1)) && actual=1
|
((actual < 1)) && actual=1
|
||||||
|
|
||||||
save_undo
|
save_undo
|
||||||
|
yankType="line"
|
||||||
yankBuffer=("${lines[@]:cursorRow:actual}")
|
yankBuffer=("${lines[@]:cursorRow:actual}")
|
||||||
hasYank=1
|
hasYank=1
|
||||||
|
|
||||||
@@ -669,6 +999,55 @@ paste_line_below() {
|
|||||||
dirty=1
|
dirty=1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paste_char_after_cursor() {
|
||||||
|
local count="$1"
|
||||||
|
local pasteRow="$cursorRow"
|
||||||
|
local pasteCol="$cursorCol"
|
||||||
|
local line prefix suffix i insertAt
|
||||||
|
|
||||||
|
if ((hasYank == 0)); then
|
||||||
|
statusMessage="Nothing in yank buffer"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$yankType" == "line" ]]; then
|
||||||
|
paste_line_below "$count"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
save_undo
|
||||||
|
if ((pasteCol < ${#lines[pasteRow]})); then
|
||||||
|
((pasteCol++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
for ((i = 0; i < count; i++)); do
|
||||||
|
line="${lines[pasteRow]}"
|
||||||
|
prefix="${line:0:pasteCol}"
|
||||||
|
suffix="${line:pasteCol}"
|
||||||
|
if ((${#yankBuffer[@]} == 1)); then
|
||||||
|
lines[pasteRow]="${prefix}${yankBuffer[0]}${suffix}"
|
||||||
|
cursorRow="$pasteRow"
|
||||||
|
cursorCol=$((pasteCol + ${#yankBuffer[0]} - 1))
|
||||||
|
pasteCol=$((cursorCol + 1))
|
||||||
|
else
|
||||||
|
lines[pasteRow]="${prefix}${yankBuffer[0]}"
|
||||||
|
insertAt=$((pasteRow + 1))
|
||||||
|
if ((${#yankBuffer[@]} > 2)); then
|
||||||
|
lines=("${lines[@]:0:insertAt}" "${yankBuffer[@]:1:${#yankBuffer[@]}-2}" "${lines[@]:insertAt}")
|
||||||
|
insertAt=$((insertAt + ${#yankBuffer[@]} - 2))
|
||||||
|
fi
|
||||||
|
lines=("${lines[@]:0:insertAt}" "${yankBuffer[-1]}${suffix}" "${lines[@]:insertAt}")
|
||||||
|
cursorRow="$insertAt"
|
||||||
|
cursorCol=$(( ${#yankBuffer[-1]} - 1 ))
|
||||||
|
pasteRow="$cursorRow"
|
||||||
|
pasteCol=$((cursorCol + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
dirty=1
|
||||||
|
statusMessage=""
|
||||||
|
clamp_cursor
|
||||||
|
}
|
||||||
|
|
||||||
save_file() {
|
save_file() {
|
||||||
local target="$1"
|
local target="$1"
|
||||||
[[ -z "$target" ]] && return 1
|
[[ -z "$target" ]] && return 1
|
||||||
@@ -756,6 +1135,7 @@ handle_command_key() {
|
|||||||
if [[ -n "$pendingCommand" ]]; then
|
if [[ -n "$pendingCommand" ]]; then
|
||||||
count="$(command_count)"
|
count="$(command_count)"
|
||||||
if [[ "$pendingCommand" == "r" ]]; then
|
if [[ "$pendingCommand" == "r" ]]; then
|
||||||
|
record_last_change "${commandCount}${pendingCommand}${key}"
|
||||||
replace_chars "$count" "$key"
|
replace_chars "$count" "$key"
|
||||||
pendingCommand=""
|
pendingCommand=""
|
||||||
commandCount=""
|
commandCount=""
|
||||||
@@ -763,27 +1143,54 @@ handle_command_key() {
|
|||||||
fi
|
fi
|
||||||
case "${pendingCommand}${key}" in
|
case "${pendingCommand}${key}" in
|
||||||
dd)
|
dd)
|
||||||
|
record_last_change "${commandCount}${pendingCommand}${key}"
|
||||||
delete_lines "$count"
|
delete_lines "$count"
|
||||||
;;
|
;;
|
||||||
d'$')
|
d'$')
|
||||||
|
record_last_change "${commandCount}${pendingCommand}${key}"
|
||||||
save_undo
|
save_undo
|
||||||
|
yank_to_end_of_line
|
||||||
delete_to_end_of_line
|
delete_to_end_of_line
|
||||||
;;
|
;;
|
||||||
dw)
|
dw)
|
||||||
|
record_last_change "${commandCount}${pendingCommand}${key}"
|
||||||
delete_word_forward "$count"
|
delete_word_forward "$count"
|
||||||
;;
|
;;
|
||||||
db)
|
db)
|
||||||
|
record_last_change "${commandCount}${pendingCommand}${key}"
|
||||||
delete_word_backward "$count"
|
delete_word_backward "$count"
|
||||||
;;
|
;;
|
||||||
|
y'$')
|
||||||
|
yank_to_end_of_line
|
||||||
|
;;
|
||||||
|
yw)
|
||||||
|
yank_word_forward "$count"
|
||||||
|
;;
|
||||||
|
yb)
|
||||||
|
yank_word_backward "$count"
|
||||||
|
;;
|
||||||
cc)
|
cc)
|
||||||
|
start_insert_change "${commandCount}${pendingCommand}${key}"
|
||||||
change_current_line
|
change_current_line
|
||||||
;;
|
;;
|
||||||
c'$')
|
c'$')
|
||||||
|
start_insert_change "${commandCount}${pendingCommand}${key}"
|
||||||
change_to_end_of_line
|
change_to_end_of_line
|
||||||
;;
|
;;
|
||||||
cw)
|
cw)
|
||||||
|
start_insert_change "${commandCount}${pendingCommand}${key}"
|
||||||
change_word "$count"
|
change_word "$count"
|
||||||
;;
|
;;
|
||||||
|
ge)
|
||||||
|
move_word_end_backward "$count"
|
||||||
|
;;
|
||||||
|
gg)
|
||||||
|
if [[ -n "$commandCount" ]]; then
|
||||||
|
move_to_line "$commandCount"
|
||||||
|
else
|
||||||
|
move_to_line 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
yy)
|
yy)
|
||||||
yank_lines "$count"
|
yank_lines "$count"
|
||||||
;;
|
;;
|
||||||
@@ -810,10 +1217,12 @@ handle_command_key() {
|
|||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
i)
|
i)
|
||||||
|
start_insert_change "${commandCount}${key}"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
enter_insert_mode
|
enter_insert_mode
|
||||||
;;
|
;;
|
||||||
a)
|
a)
|
||||||
|
start_insert_change "${commandCount}${key}"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
if ((cursorCol < $(line_length "$cursorRow"))); then
|
if ((cursorCol < $(line_length "$cursorRow"))); then
|
||||||
((cursorCol++))
|
((cursorCol++))
|
||||||
@@ -821,11 +1230,13 @@ handle_command_key() {
|
|||||||
enter_insert_mode
|
enter_insert_mode
|
||||||
;;
|
;;
|
||||||
I)
|
I)
|
||||||
|
start_insert_change "${commandCount}${key}"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
cursorCol=0
|
cursorCol=0
|
||||||
enter_insert_mode
|
enter_insert_mode
|
||||||
;;
|
;;
|
||||||
A)
|
A)
|
||||||
|
start_insert_change "${commandCount}${key}"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
cursorCol="$(line_length "$cursorRow")"
|
cursorCol="$(line_length "$cursorRow")"
|
||||||
enter_insert_mode
|
enter_insert_mode
|
||||||
@@ -865,27 +1276,46 @@ handle_command_key() {
|
|||||||
move_word_backward "$count"
|
move_word_backward "$count"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
;;
|
;;
|
||||||
|
G)
|
||||||
|
if [[ -n "$commandCount" ]]; then
|
||||||
|
move_to_line "$commandCount"
|
||||||
|
else
|
||||||
|
move_to_line "${#lines[@]}"
|
||||||
|
fi
|
||||||
|
commandCount=""
|
||||||
|
;;
|
||||||
|
'^')
|
||||||
|
commandCount=""
|
||||||
|
move_to_first_nonblank
|
||||||
|
;;
|
||||||
'$')
|
'$')
|
||||||
commandCount=""
|
commandCount=""
|
||||||
cursorCol="$(line_length "$cursorRow")"
|
cursorCol="$(line_length "$cursorRow")"
|
||||||
;;
|
;;
|
||||||
x)
|
x)
|
||||||
count="$(command_count)"
|
count="$(command_count)"
|
||||||
|
record_last_change "${commandCount}${key}"
|
||||||
save_undo
|
save_undo
|
||||||
|
yank_range "$cursorRow" "$cursorCol" "$cursorRow" "$((cursorCol + count))"
|
||||||
for ((i = 0; i < count; i++)); do delete_under_cursor; done
|
for ((i = 0; i < count; i++)); do delete_under_cursor; done
|
||||||
commandCount=""
|
commandCount=""
|
||||||
;;
|
;;
|
||||||
D)
|
D)
|
||||||
|
record_last_change "${commandCount}${key}"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
save_undo
|
save_undo
|
||||||
|
yank_to_end_of_line
|
||||||
delete_to_end_of_line
|
delete_to_end_of_line
|
||||||
;;
|
;;
|
||||||
C)
|
C)
|
||||||
|
start_insert_change "${commandCount}${key}"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
change_to_end_of_line
|
change_to_end_of_line
|
||||||
;;
|
;;
|
||||||
s)
|
s)
|
||||||
count="$(command_count)"
|
count="$(command_count)"
|
||||||
|
start_insert_change "${commandCount}${key}"
|
||||||
|
yank_range "$cursorRow" "$cursorCol" "$cursorRow" "$((cursorCol + count))"
|
||||||
substitute_chars "$count"
|
substitute_chars "$count"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
;;
|
;;
|
||||||
@@ -893,27 +1323,61 @@ handle_command_key() {
|
|||||||
pendingCommand="$key"
|
pendingCommand="$key"
|
||||||
statusMessage=""
|
statusMessage=""
|
||||||
;;
|
;;
|
||||||
d|y|c)
|
d|y|c|g)
|
||||||
pendingCommand="$key"
|
pendingCommand="$key"
|
||||||
statusMessage=""
|
statusMessage=""
|
||||||
;;
|
;;
|
||||||
p)
|
p)
|
||||||
count="$(command_count)"
|
count="$(command_count)"
|
||||||
paste_line_below "$count"
|
record_last_change "${commandCount}${key}"
|
||||||
|
paste_char_after_cursor "$count"
|
||||||
|
commandCount=""
|
||||||
|
;;
|
||||||
|
J)
|
||||||
|
count="$(command_count)"
|
||||||
|
record_last_change "${commandCount}${key}"
|
||||||
|
join_lines "$count"
|
||||||
commandCount=""
|
commandCount=""
|
||||||
;;
|
;;
|
||||||
o)
|
o)
|
||||||
count="$(command_count)"
|
count="$(command_count)"
|
||||||
|
start_insert_change "${commandCount}${key}"
|
||||||
save_undo
|
save_undo
|
||||||
for ((i = 0; i < count; i++)); do open_line_below; done
|
for ((i = 0; i < count; i++)); do open_line_below; done
|
||||||
commandCount=""
|
commandCount=""
|
||||||
;;
|
;;
|
||||||
O)
|
O)
|
||||||
count="$(command_count)"
|
count="$(command_count)"
|
||||||
|
start_insert_change "${commandCount}${key}"
|
||||||
save_undo
|
save_undo
|
||||||
for ((i = 0; i < count; i++)); do open_line_above; done
|
for ((i = 0; i < count; i++)); do open_line_above; done
|
||||||
commandCount=""
|
commandCount=""
|
||||||
;;
|
;;
|
||||||
|
/)
|
||||||
|
commandCount=""
|
||||||
|
prompt_search forward
|
||||||
|
;;
|
||||||
|
'?')
|
||||||
|
commandCount=""
|
||||||
|
prompt_search backward
|
||||||
|
;;
|
||||||
|
n)
|
||||||
|
commandCount=""
|
||||||
|
repeat_search "$lastSearchDirection"
|
||||||
|
;;
|
||||||
|
N)
|
||||||
|
commandCount=""
|
||||||
|
if [[ "$lastSearchDirection" == "forward" ]]; then
|
||||||
|
repeat_search backward
|
||||||
|
else
|
||||||
|
repeat_search forward
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
'.')
|
||||||
|
count="$(command_count)"
|
||||||
|
commandCount=""
|
||||||
|
repeat_last_change "$count"
|
||||||
|
;;
|
||||||
:)
|
:)
|
||||||
commandCount=""
|
commandCount=""
|
||||||
prompt_command
|
prompt_command
|
||||||
@@ -940,38 +1404,47 @@ handle_insert_key() {
|
|||||||
local key="$1"
|
local key="$1"
|
||||||
case "$key" in
|
case "$key" in
|
||||||
$'\033')
|
$'\033')
|
||||||
|
finish_insert_change
|
||||||
mode="command"
|
mode="command"
|
||||||
insertUndoSaved=0
|
insertUndoSaved=0
|
||||||
statusMessage=""
|
statusMessage=""
|
||||||
;;
|
;;
|
||||||
$'\033[D')
|
$'\033[D')
|
||||||
|
insertChangeKeys+="$key"
|
||||||
move_left
|
move_left
|
||||||
;;
|
;;
|
||||||
$'\033[C')
|
$'\033[C')
|
||||||
|
insertChangeKeys+="$key"
|
||||||
move_right
|
move_right
|
||||||
;;
|
;;
|
||||||
$'\033[A')
|
$'\033[A')
|
||||||
|
insertChangeKeys+="$key"
|
||||||
move_up
|
move_up
|
||||||
;;
|
;;
|
||||||
$'\033[B')
|
$'\033[B')
|
||||||
|
insertChangeKeys+="$key"
|
||||||
move_down
|
move_down
|
||||||
;;
|
;;
|
||||||
$'\r'|$'\n')
|
$'\r'|$'\n')
|
||||||
|
insertChangeKeys+="$key"
|
||||||
split_line
|
split_line
|
||||||
;;
|
;;
|
||||||
$'\177'|$'\b')
|
$'\177'|$'\b')
|
||||||
|
insertChangeKeys+="$key"
|
||||||
backspace_insert
|
backspace_insert
|
||||||
;;
|
;;
|
||||||
$'\007')
|
$'\007')
|
||||||
file_info
|
file_info
|
||||||
;;
|
;;
|
||||||
$'\003')
|
$'\003')
|
||||||
|
finish_insert_change
|
||||||
mode="command"
|
mode="command"
|
||||||
insertUndoSaved=0
|
insertUndoSaved=0
|
||||||
statusMessage="Use :q to quit"
|
statusMessage="Use :q to quit"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if [[ "$key" =~ [[:print:]] ]]; then
|
if [[ "$key" =~ [[:print:]] ]]; then
|
||||||
|
insertChangeKeys+="$key"
|
||||||
insert_char "$key"
|
insert_char "$key"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|||||||
Reference in New Issue
Block a user