From 67fc567939eec10fcea47cd3569d1682698a5724 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Mon, 21 Oct 2024 22:39:32 +0200 Subject: feat(modules/zsh): Nearly completely rewrite New features: - The `vi` mode is now actually useful - The whole history search/suggestion has been integrated into `atuin` - The `edit-command-line` plugin does no longer print useless stuff - and miscellaneous other things. --- modules/by-name/zs/zsh/config/command_not_found.sh | 64 -- .../config/command_not_found/command_not_found.sh | 64 ++ .../command_not_found/command_not_found_insult.sh | 298 ++++++++++ .../zs/zsh/config/command_not_found_insult.sh | 298 ---------- modules/by-name/zs/zsh/config/custom_cursor.zsh | 81 +-- .../by-name/zs/zsh/config/edit_command_line.zsh | 25 + modules/by-name/zs/zsh/config/keymaps/.safe.zsh | 5 + modules/by-name/zs/zsh/config/keymaps/command.zsh | 6 + modules/by-name/zs/zsh/config/keymaps/emacs.zsh | 119 ++++ modules/by-name/zs/zsh/config/keymaps/isearch.zsh | 2 + modules/by-name/zs/zsh/config/keymaps/vicmd.zsh | 156 +++++ modules/by-name/zs/zsh/config/keymaps/viins.zsh | 55 ++ modules/by-name/zs/zsh/config/keymaps/viopp.zsh | 45 ++ modules/by-name/zs/zsh/config/keymaps/visual.zsh | 53 ++ modules/by-name/zs/zsh/config/keymaps_end.zsh | 2 + modules/by-name/zs/zsh/config/keymaps_start.zsh | 16 + modules/by-name/zs/zsh/config/zsh-init.zsh | 37 +- modules/by-name/zs/zsh/module.nix | 106 ++-- .../zsh/plugins/zsh-history-substring-search.zsh | 648 +++++++++++++++++++++ 19 files changed, 1604 insertions(+), 476 deletions(-) delete mode 100644 modules/by-name/zs/zsh/config/command_not_found.sh create mode 100644 modules/by-name/zs/zsh/config/command_not_found/command_not_found.sh create mode 100644 modules/by-name/zs/zsh/config/command_not_found/command_not_found_insult.sh delete mode 100644 modules/by-name/zs/zsh/config/command_not_found_insult.sh create mode 100644 modules/by-name/zs/zsh/config/edit_command_line.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps/.safe.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps/command.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps/emacs.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps/isearch.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps/vicmd.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps/viins.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps/viopp.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps/visual.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps_end.zsh create mode 100644 modules/by-name/zs/zsh/config/keymaps_start.zsh create mode 100644 modules/by-name/zs/zsh/plugins/zsh-history-substring-search.zsh (limited to 'modules/by-name/zs') diff --git a/modules/by-name/zs/zsh/config/command_not_found.sh b/modules/by-name/zs/zsh/config/command_not_found.sh deleted file mode 100644 index fb21b676..00000000 --- a/modules/by-name/zs/zsh/config/command_not_found.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env dash - -# This was taken from the -# `${pkgs.nix-index}/etc/profile.d/command-not-found.sh` file on 2024-02-28 - -# for bash 4 -# this will be called when a command is entered -# but not found in the user’s path + environment -command_not_found_handle() { - # taken from http://www.linuxjournal.com/content/bash-command-not-found - # - do not run when inside Midnight Commander or within a Pipe - if [ -n "${MC_SID-}" ] || ! [ -t 1 ]; then - >&2 echo "$1: command not found" - return 127 - fi - - toplevel=nixpkgs # nixpkgs should always be available even in NixOS - cmd="$1" - attrs=$(nix-locate --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$cmd") - len=$(if [ -n "$attrs" ]; then echo "$attrs" | wc -l; else echo 0; fi) - - case "$len" in - 0) - eprintln "$cmd: command not found" - ;; - 1) - # If only one package provides this, then we can invoke it - # without asking the user. - - # These will not return 127 if they worked correctly. - - >&2 cat <&2 cat <&2 cat <&2 echo "$1: command not found" + return 127 + fi + + toplevel=nixpkgs # nixpkgs should always be available even in NixOS + cmd="$1" + attrs=$(nix-locate --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$cmd") + len=$(if [ -n "$attrs" ]; then echo "$attrs" | wc -l; else echo 0; fi) + + case "$len" in + 0) + eprintln "$cmd: command not found" + ;; + 1) + # If only one package provides this, then we can invoke it + # without asking the user. + + # These will not return 127 if they worked correctly. + + >&2 cat <&2 cat <&2 cat <&2 + fi +} + +function_exists() { + # Zsh returns 0 even on non existing functions with -F so use -f + declare -f "$1" >/dev/null + return $? +} + +# +# The idea below is to copy any existing handlers to another function +# name and insert the message in front of the old handler in the +# new handler. By default, neither bash or zsh has has a handler function +# defined, so the default behaviour is replicated. +# +# Also, ensure the handler is only copied once. If we do not ensure this +# the handler would add itself recursively if this file happens to be +# sourced multiple times in the same shell, resulting in a neverending +# stream of messages. +# + +# +# Zsh +# +if function_exists command_not_found_handler; then + if ! function_exists orig_command_not_found_handler; then + eval "orig_$(declare -f command_not_found_handler)" + fi +else + orig_command_not_found_handler() { + printf "zsh: command not found: %s\n" "$1" >&2 + return 127 + } +fi + +command_not_found_handler() { + print_message + orig_command_not_found_handler "$@" +} + +# +# Bash +# +if function_exists command_not_found_handle; then + if ! function_exists orig_command_not_found_handle; then + eval "orig_$(declare -f command_not_found_handle)" + fi +else + orig_command_not_found_handle() { + printf "%s: %s: command not found\n" "$0" "$1" >&2 + return 127 + } +fi + +command_not_found_handle() { + print_message + orig_command_not_found_handle "$@" +} diff --git a/modules/by-name/zs/zsh/config/command_not_found_insult.sh b/modules/by-name/zs/zsh/config/command_not_found_insult.sh deleted file mode 100644 index 5126845a..00000000 --- a/modules/by-name/zs/zsh/config/command_not_found_insult.sh +++ /dev/null @@ -1,298 +0,0 @@ -#! /usr/bin/env bash -print_message() { - - local messages - local message - - ### STANDARD INSULTS ### - declare -a _array1=( - "(╯°□°)╯︵ ┻━┻" - "¯\_(ツ)_/¯" - "ACHTUNG! ALLES TURISTEN UND NONTEKNISCHEN LOOKENPEEPERS! DAS KOMPUTERMASCHINE IST NICHT FÜR DER GEFINGERPOKEN UND MITTENGRABEN! ODERWISE IST EASY TO SCHNAPPEN DER SPRINGENWERK, BLOWENFUSEN UND POPPENCORKEN MIT SPITZENSPARKEN. IST NICHT FÜR GEWERKEN BEI DUMMKOPFEN. DER RUBBERNECKEN SIGHTSEEREN KEEPEN DAS COTTONPICKEN HÄNDER IN DAS POCKETS MUSS. ZO RELAXEN UND WATSCHEN DER BLINKENLICHTEN." - "And the Darwin Award goes to.... ${USER}!" - "Allowing you to survive childbirth was medical malpractice." - "Are you always this stupid or are you making a special effort today?!" - "Are you even trying?!" - "Bad." - "Boooo!" - "Brains aren't everything. In your case they're nothing." - "Commands, random gibberish, who cares!" - "Come on! You can do it!" - "Don't you have anything better to do?!" - "Don't you know anything?" - "Dropped on your head as a baby, eh?" - "error code: 1D10T" - "Even your mom loves you only as a friend." - "ERROR_INCOMPETENT_USER" - "Fake it till you make it!" - "Go outside." - "Haha, n00b!" - "How many times do I have to flush before you go away?" - "I am _seriously_ considering 'rm -rf /'-ing myself..." - "I don't know what makes you so stupid, but it really works." - "I was going to give you a nasty look, but I see you already have one." - "If beauty fades then you have nothing to worry about." - "If brains were gasoline you wouldn’t have enough to propel a flea’s motorcycle around a doughnut." - "If ignorance is bliss, you must be the happiest person on earth." - "If shit was music, you'd be an orchestra." - "If what you don't know can't hurt you, you're invulnerable." - "Incompetence is also a form of competence" - "I’d slap you, but that’d be animal abuse." - "I’ve heard of being hit with the ugly stick, but you must have been beaten senseless with it." - "Keep trying, someday you'll do something intelligent!" - "Let’s play horse. I’ll be the front end. And you be yourself." - "Life is good, you should get one." - "lol" - "lol... plz" - "My keyboard is not a touch screen!" - "My uptime is longer than your relationships." - "Nice try." - "n00b alert!" - "Pathetic" - "Perhaps computers are not for you..." - "Perhaps you should leave the command line alone..." - "Please step away from the keyboard!" - "plz uninstall" - "Pro tip: type a valid command!" - "Rose are red. Violets are blue. I have five fingers. The middle one's for you." - "RTFM!" - "Sorry what? I don’t understand idiot language." - "The degree of your stupidity is enough to boil water." - "The worst one today!" - "This is not a search engine." - "This is not Windows" - "This is why nobody likes you." - "This is why you get to see your children only once a month." - "Try using your brain the next time!" - "Two wrongs don't make a right, take your parents as an example." - "Typing incorrect commands, eh?" - "u suk" - "What if... you type an actual command the next time!" - "What if I told you... it is possible to type valid commands." - "What is this...? Amateur hour!?" - "Why are you so stupid?!" - "Why are you doing this to me?!" - "Why did the chicken cross the road? To get the hell away from you." - "Wow! That was impressively wrong!" - "Y u no speak computer???" - "You are not as bad as people say, you are much, much worse." - "You are not useless since you can still be used as a bad example." - "You must have been born on a highway because that's where most accidents happen." - "Your application for reduced salary has been sent!" - "Your mom had a severe case of diarrhea when you were born." - "You're proof that god has a sense of humor." - "You’re so dumb your first words were DUH." - "You're so fat, people jog around you for exercise." - "You’re the reason Santa says ho, ho, ho, on Christmas!" - ) - ### SHAKESPEARE INSULTS ### - declare -a array2=( - "A most notable coward, an infinite and endless liar, an hourly promise breaker, the owner of no one good quality." - "Away, you starvelling, you elf-skin, you dried neat's-tongue, bull's-pizzle, you stock-fish!" - "Away, you three-inch fool! " - "Come, come, you froward and unable worms!" - "Go, prick thy face, and over-red thy fear, Thou lily-liver’d boy." - "His wit's as thick as a Tewkesbury mustard." - "I am pigeon-liver'd and lack gall." - "I am sick when I do look on thee " - "I must tell you friendly in your ear, sell when you can, you are not for all markets." - "If thou wilt needs marry, marry a fool; for wise men know well enough what monsters you make of them." - "I'll beat thee, but I would infect my hands." - "I scorn you, scurvy companion. " - "Methink'st thou art a general offence and every man should beat thee." - "More of your conversation would infect my brain." - "My wife's a hobby horse!" - "Peace, ye fat guts!" - "Poisonous bunch-backed toad! " - "The rankest compound of villainous smell that ever offended nostril" - "The tartness of his face sours ripe grapes." - "There's no more faith in thee than in a stewed prune." - "Thine forward voice, now, is to speak well of thine friend; thine backward voice is to utter foul speeches and to detract." - "That trunk of humours, that bolting-hutch of beastliness, that swollen parcel of dropsies, that huge bombard of sack, that stuffed cloak-bag of guts, that roasted Manningtree ox with pudding in his belly, that reverend vice, that grey Iniquity, that father ruffian, that vanity in years?" - "Thine face is not worth sunburning." - "This woman's an easy glove, my lord, she goes off and on at pleasure." - "Thou art a boil, a plague sore." - "Was the Duke a flesh-monger, a fool and a coward?" - "Thou art as fat as butter." - "Here is the babe, as loathsome as a toad." - "Like the toad; ugly and venomous." - "Thou art unfit for any place but hell." - "Thou cream faced loon" - "Thou clay-brained guts, thou knotty-pated fool, thou whoreson obscene greasy tallow-catch!" - "Thou damned and luxurious mountain goat." - "Thou elvish-mark'd, abortive, rooting hog!" - "Thou leathern-jerkin, crystal-button, knot-pated, agatering, puke-stocking, caddis-garter, smooth-tongue, Spanish pouch!" - "Thou lump of foul deformity" - "That poisonous bunch-back'd toad!" - "Thou sodden-witted lord! Thou hast no more brain than I have in mine elbows " - "Thou subtle, perjur'd, false, disloyal man!" - "Thou whoreson zed , thou unnecessary letter!" - "Thy sin’s not accidental, but a trade." - "Thy tongue outvenoms all the worms of Nile." - "Would thou wert clean enough to spit upon" - "Would thou wouldst burst!" - "You poor, base, rascally, cheating lack-linen mate! " - "You are as a candle, the better burnt out." - "You scullion! You rampallian! You fustilarian! I’ll tickle your catastrophe!" - "You starvelling, you eel-skin, you dried neat's-tongue, you bull's-pizzle, you stock-fish-O for breath to utter what is like thee!-you tailor's-yard, you sheath, you bow-case, you vile standing tuck!" - "Your brain is as dry as the remainder biscuit after voyage." - "Virginity breeds mites, much like a cheese." - "Villain, I have done thy mother" - ) - ### MARTIN LUTHER INSULTS ### - declare -a array3=( - "You live like simple cattle or irrational pigs and, despite the fact that the gospel has returned, have mastered the fine art of misusing all your freedom." - "You shameful gluttons and servants of your bellies are better suited to be swineherds and keepers of dogs." - "You deserve not only to be given no food to eat, but also to have the dogs set upon you and to be pelted with horse manure." - "Oh, what mad senseless fools you are!" - "For this you deserve to have God deprive you of his Word and blessing and once again allow preachers of lies to arise who lead you to the devil - and wring sweat and blood out of you besides." - "All your holiness is only stench and filth, and it merits nothing but wrath and damnation." - "May your grain spoil in the barn, your beer in the cellar, your cattle perish in the stall. Yes, your entire hoard ought to be consumed by rust so that you will never enjoy it." - "You relish and delight in the chance to stir up someone else's dirt like pigs that roll in manure and root around in it with their snouts." - "Your sin smells to high heaven." - "Your words are so foolishly and ignorantly composed that I cannot believe you understand them." - "You are the most insane heretics and ingrafters of heretical perversity." - "What you say is a blasphemy that has made you worthy of a thousand deaths." - "Behold, indeed, this little golden work of a golden teacher! It is a work most worthy of golden letters, and lest there be something about it which is not golden, it must be handed down by golden disciples, namely, by those about whom it is said, 'The idols of the nations are silver and gold. They have eyes, but they see not.'" - "You are worthy only to be mocked by the words of error." - "It is presumptuous for people who are as ignorant as you are not to take up the work of a herdsman." - "What bilgewater of heresies has ever been spoken so heretically as what you have said?" - "What do you mean when you say this? Are you dreaming in the throes of a fever or are you laboring under a madness?" - "Your astute minds have been completely turned into stinking mushrooms." - "You are the prostitute of heretics!" - "I am tired of the pestilent voice of your sirens." - "You are a bungling magpie, croaking loudly." - "You forgot to purge yourself with hellabore while you were preparing to fabricate this lie." - "You are more corrupt than any Babylon or Sodom ever was, and, as far as I can see, are characterized by a completely depraved, hopeless, and notorious godlessness." - "Your home, once the holiest of all, has become the most licentious den of thieves, the most shameless of all brothels, the kingdom of sin, death, and hell. It is so bad that even Antichrist himself, if he should come, could think of nothing to add to its wickedness." - "What devilish unchristian thing would you not undertake?" - "You are an extraordinary creature, being neither God nor man. Perhaps you are the devil himself." - "Even if the Antichrist appears, what greater evil can he do than what you have done and do daily?" - "It may be that you want to build yourself a heaven of your own, like those jugglers build themselves out of linen cloth at the Shrove Tuesday carnival. Is it not disgusting that we have to hear such foolish and childish things from you?" - "In our country, fruit grows on trees and from trees, and meditation upon sin grows from contrition. But in your land, trees may grow on fruits, contrition from sins, people walk on their ears, and everything is upside down." - "O you wolf in Christendom!" - "You know less than does a log on the ground." - "I think that all the devils have at once entered into you." - "You are worse than all the devils. What you have done, no devil has ever done. Your end is near, you son of perdition and Antichrist! Stop now, you are going to far!" - "You are the true, chief, and final Antichrist." - "How far will you go, O devilish pride?" - "All Christians should be on guard against your antichristian poison." - "I think you received these ideas in your pipe dreams." - "You are in all you do the very opposite of Christ as befits a true Antichrist." - "You are a person of sin and the child of perdition, leading all the world with you to the devil, using your lying and deceitful ways." - "You are not a pious fraud, but an infernal, diabolical, antichristian fraud." - "You are the Roman Nimrod and a teacher of sin." - "It is the old dragon from the abyss of hell who is standing before me!" - "You hold fast to human dreams and the doctrines of devils." - "If you who are assembled in a council are so frivolous and irresponsible as to waste time and money on unnecessary questions, when it is the business of a council to deal only with the important and necessary matters, we should not only refuse to obey you, but consider you insane or criminals." - "Even Lucifer was not guilty of so great a sacrilege in heaven, for he only presumed to be God's equal. God help us!" - "You condemned the holy gospel and replaced it with the teaching of the dragon from hell." - "Your words are un-Christian, antichristian, and spoken by the inspiration of the evil spirit." - "What happened to the house built on sand in Matthew 7 will also happen to you." - "Must we believe your nightmares?" - "Look how this great heretic speaks brazenly and sacrilegiously." - "You run against God with the horns of your pride up in the air and thus plunge into the abyss of hell. Woe unto you, Antichrist!" - "You are the devil's most dangerous tool!" - "It seems I must have liars and villains for opponents. I am not worthy in the sight of God that a godly and honorable person should discuss these matters with me in a Christian way. This is my greatest lament." - "May the Lord Jesus protect me and all devout souls from your contagion and your company!" - "This venom - the mere smell of which kills a man!" - "You are a Baal-zebub - that is, a man of flies." - "You are full of poisonous refuse and insane foolishness." - "You are ignorant, stupid, godless blasphemers." - "You moderate enforcer and eulogizer of moderation. You are one of those bloody and deceitful people who affect modesty in words and appearance, but who meanwhile breathe out threats and blood." - "We leave you to your own devices, for nothing properly suits you except hypocrisy, flattery, and lies." - "In lying fashion you ignore what even children know." - "The reward of such flattery is what your crass stupidity deserves. Therefore, we shall turn from you, a sevenfold stupid and blasphemous wise person." - "People of your sort are hirelings, dumb dogs unable to bark, who see the wolf coming and flee or, rather, join up with the wolf." - "You are a wolf and apostle of Satan." - "You are the ultimate scourges of the world, the Antichrist together with your sophists and bishops." - "You cowardly slave, you corrupt sycophant, with your sickening advice!" - "You are idiots and swine." - "Every letter of yours breathes Moabitish pride. So much can a single bull inflate a single bubble that you practically make distinguished asses into gods." - "You sophistic worms, grasshoppers, locusts, frogs and lice!" - 'You completely close your mind and do nothing but shout, "Anathema, anathema, anathema!" so that by your own voice you are judged mad.' - "Let this generation of vipers prepare itself for unquenchable fire!" - "You rush forward as an ass under the pelt of a lion." - "In appearance and words you simulate modesty, but you are so swollen with haughtiness, arrogance, pride, malice, villainy, rashness, superciliousness, ignorance, and stupidity that there is nothing to surpass you." - "Blind moles!" - "We despise your whorish impudence." - ) - ### EDIT THIS LINE IF YOU ONLY WANT TO USE CERTAIN INSULT LISTS ### - messages=( - # "${array1[@]}" ## normal ones - "${array2[@]}" ## Shakespeare - "${array3[@]}" ## Luther - ) - - # If CMD_NOT_FOUND_MSGS array is populated use those messages instead of the defaults - [[ -n ${CMD_NOT_FOUND_MSGS} ]] && messages=("${CMD_NOT_FOUND_MSGS[@]}") - - # If CMD_NOT_FOUND_MSGS_APPEND array is populated append those to the existing messages - [[ -n ${CMD_NOT_FOUND_MSGS_APPEND} ]] && messages+=("${CMD_NOT_FOUND_MSGS_APPEND[@]}") - - # Seed RANDOM with an integer of some length - RANDOM=$(od -vAn -N4 -tu &2 - fi -} - -function_exists() { - # Zsh returns 0 even on non existing functions with -F so use -f - declare -f "$1" >/dev/null - return $? -} - -# -# The idea below is to copy any existing handlers to another function -# name and insert the message in front of the old handler in the -# new handler. By default, neither bash or zsh has has a handler function -# defined, so the default behaviour is replicated. -# -# Also, ensure the handler is only copied once. If we do not ensure this -# the handler would add itself recursively if this file happens to be -# sourced multiple times in the same shell, resulting in a neverending -# stream of messages. -# - -# -# Zsh -# -if function_exists command_not_found_handler; then - if ! function_exists orig_command_not_found_handler; then - eval "orig_$(declare -f command_not_found_handler)" - fi -else - orig_command_not_found_handler() { - printf "zsh: command not found: %s\n" "$1" >&2 - return 127 - } -fi - -command_not_found_handler() { - print_message - orig_command_not_found_handler "$@" -} - -# -# Bash -# -if function_exists command_not_found_handle; then - if ! function_exists orig_command_not_found_handle; then - eval "orig_$(declare -f command_not_found_handle)" - fi -else - orig_command_not_found_handle() { - printf "%s: %s: command not found\n" "$0" "$1" >&2 - return 127 - } -fi - -command_not_found_handle() { - print_message - orig_command_not_found_handle "$@" -} diff --git a/modules/by-name/zs/zsh/config/custom_cursor.zsh b/modules/by-name/zs/zsh/config/custom_cursor.zsh index 37390c1c..071bb5fe 100644 --- a/modules/by-name/zs/zsh/config/custom_cursor.zsh +++ b/modules/by-name/zs/zsh/config/custom_cursor.zsh @@ -1,42 +1,53 @@ #!/usr/bin/env zsh -# Change cursor shape for different vi modes. -function zle-keymap-select { - if [[ ${KEYMAP} == vicmd ]] || - [[ $1 = 'block' ]]; then - echo -ne '\e[1 q' - elif [[ ${KEYMAP} == main ]] || - [[ ${KEYMAP} == viins ]] || - [[ ${KEYMAP} = '' ]] || - [[ $1 = 'beam' ]]; then - echo -ne '\e[5 q' - fi -} -zle -N zle-keymap-select +autoload -U add-zsh-hook +autoload -U add-zle-hook-widget + +_cursor_beam() { echo -ne "\\033[5 q" } +_cursor_block() { echo -ne "\\033[1 q" } -# ci", ci', ci`, di", etc -autoload -U select-quoted -zle -N select-quoted -for m in visual viopp; do - for c in {a,i}{\',\",\`}; do - bindkey -M "$m" "$c" select-quoted - done -done +# Change cursor shape for different vi modes. +# From `ZSHZLE (1)`: +# > Executed every time the keymap changes, i.e. the special parameter KEYMAP is set to a different value, +# > while the line editor is active. Initialising the keymap when the line editor starts does +# > not cause the widget to be called. +# > +# > The value $KEYMAP within the function reflects the new keymap. The old keymap is passed as the sole argument. +# > +# > This can be used for detecting switches between the vi command (vicmd) and insert (usually main) keymaps. +_cursor_zle-keymap-select() { + : keymap select -# ci{, ci(, ci<, di{, etc -autoload -U select-bracketed -zle -N select-bracketed -for m in visual viopp; do - for c in {a,i}${(s..)^:-'()[]{}<>bB'}; do - bindkey -M $m $c select-bracketed - done -done + case "$KEYMAP" in + "vicmd" | "block") + _cursor_block + ;; + "main" | "viins" | "" | "beam") + _cursor_beam + ;; + esac +} +add-zle-hook-widget keymap-select _cursor_zle-keymap-select -zle-line-init() { - zle -K viins # initiate `vi insert` as keymap (can be removed if `bindkey -V` has been set elsewhere) - echo -ne "\e[5 q" +# From `ZSHZLE(1)`: +# > Executed every time the line editor is started to read a new line of input. +# > The following example puts the line editor into vi command mode when it starts up. +# > +# > zle-line-init() { zle -K vicmd; } +# > zle -N zle-line-init +# > +# > (The command inside the function sets the keymap directly; it is equivalent to zle vi-cmd-mode.) +_cursor_zle-line-init() { + : zle line init + _cursor_beam +} +# > This is similar to zle-line-init but is executed every time the line editor has finished reading a line of input. +_cursor_zle-line-finish() { + : zle line finish + _cursor_block } -zle -N zle-line-init +add-zle-hook-widget line-init _cursor_zle-line-init +add-zle-hook-widget line-finish _cursor_zle-line-finish -echo -ne '\e[5 q' # Use beam shape cursor on startup. -precmd() { echo -ne '\e[5 q' ;} # Use beam shape cursor for each new prompt. +# Use beam shape cursor on startup. +_cursor_beam diff --git a/modules/by-name/zs/zsh/config/edit_command_line.zsh b/modules/by-name/zs/zsh/config/edit_command_line.zsh new file mode 100644 index 00000000..1d51a4e8 --- /dev/null +++ b/modules/by-name/zs/zsh/config/edit_command_line.zsh @@ -0,0 +1,25 @@ +#! /usr/bin/env zsh + +autoload -Uz edit-command-line + +wrapped_edit-command-line() { + # This overrides a print implementation in my shell lib + print() { + # FIXME: `print` is called in the following way from `edit-command-line` + # (from: https://raw.githubusercontent.com/zsh-users/zsh/refs/heads/master/Functions/Zle/edit-command-line): + # ``` + # (( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[1] + # ``` + # This results in the error, that the `-r|-n` arguments are mutually exclusive with + # the `-` arg. I'm sure, that this is not a bug (as it's been in there for quite + # some time now), and ignoring it just seems to work. + # But I should either really fix this or find a explanation *why* they are doing + # it. <2024-10-21> + builtin print "$*" 2>/dev/null + } + + # Execute the original `edit-command-line` + edit-command-line +} + +zle -N edit-command-line wrapped_edit-command-line diff --git a/modules/by-name/zs/zsh/config/keymaps/.safe.zsh b/modules/by-name/zs/zsh/config/keymaps/.safe.zsh new file mode 100644 index 00000000..ee3bfa32 --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps/.safe.zsh @@ -0,0 +1,5 @@ +bindkey -M .safe "^J" .accept-line +bindkey -M .safe "^M" .accept-line +bindkey -R -M .safe "^@"-"^I" .self-insert +bindkey -R -M .safe "^K"-"^L" .self-insert +bindkey -R -M .safe "^N"-"\M-^?" .self-insert diff --git a/modules/by-name/zs/zsh/config/keymaps/command.zsh b/modules/by-name/zs/zsh/config/keymaps/command.zsh new file mode 100644 index 00000000..81ae6dda --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps/command.zsh @@ -0,0 +1,6 @@ +# Keymap used in the vicmd `execute-named-cmd` mode +bindkey -N command + +bindkey -M command "^J" accept-line +bindkey -M command "^M" accept-line +bindkey -M command "^G" send-break diff --git a/modules/by-name/zs/zsh/config/keymaps/emacs.zsh b/modules/by-name/zs/zsh/config/keymaps/emacs.zsh new file mode 100644 index 00000000..b789faf5 --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps/emacs.zsh @@ -0,0 +1,119 @@ +bindkey -N emacs + +bindkey -M emacs "^[A" accept-and-hold +bindkey -M emacs "^[a" accept-and-hold +bindkey -M emacs "^J" accept-line +bindkey -M emacs "^M" accept-line +bindkey -M emacs "^O" accept-line-and-down-history +bindkey -M emacs "^R" atuin-search +bindkey -M emacs "^[OA" atuin-up-search +bindkey -M emacs "^[[A" atuin-up-search +bindkey -M emacs "^B" backward-char +bindkey -M emacs "^[OD" backward-char +bindkey -M emacs "^[[D" backward-char +bindkey -M emacs "^?" backward-delete-char +bindkey -M emacs "^H" backward-delete-char +bindkey -M emacs "^W" backward-kill-word +bindkey -M emacs "^[^?" backward-kill-word +bindkey -M emacs "^[^H" backward-kill-word +bindkey -M emacs "^[B" backward-word +bindkey -M emacs "^[b" backward-word +bindkey -M emacs "^[<" beginning-of-buffer-or-history +bindkey -M emacs "^A" beginning-of-line +bindkey -M emacs "^[[200~" bracketed-paste +bindkey -M emacs "^[C" capitalize-word +bindkey -M emacs "^L" clear-screen +bindkey -M emacs "^[^L" clear-screen +bindkey -M emacs "^[^_" copy-prev-word +bindkey -M emacs "^[W" copy-region-as-kill +bindkey -M emacs "^[w" copy-region-as-kill +bindkey -M emacs "^D" delete-char-or-list +bindkey -M emacs "^[0" digit-argument +bindkey -M emacs "^[1" digit-argument +bindkey -M emacs "^[2" digit-argument +bindkey -M emacs "^[3" digit-argument +bindkey -M emacs "^[4" digit-argument +bindkey -M emacs "^[5" digit-argument +bindkey -M emacs "^[6" digit-argument +bindkey -M emacs "^[7" digit-argument +bindkey -M emacs "^[8" digit-argument +bindkey -M emacs "^[9" digit-argument +bindkey -M emacs "^[L" down-case-word +bindkey -M emacs "^[l" down-case-word +bindkey -M emacs "^N" down-line-or-history +bindkey -M emacs "^[OB" down-line-or-history +bindkey -M emacs "^[[B" down-line-or-history +bindkey -M emacs "^[>" end-of-buffer-or-history +bindkey -M emacs "^E" end-of-line +bindkey -M emacs "^X^X" exchange-point-and-mark +bindkey -M emacs "^[z" execute-last-named-cmd +bindkey -M emacs "^[x" execute-named-cmd +bindkey -M emacs "^[ " expand-history +bindkey -M emacs "^[!" expand-history +bindkey -M emacs "^I" expand-or-complete +bindkey -M emacs "^X*" expand-word +bindkey -M emacs "^F" forward-char +bindkey -M emacs "^[OC" forward-char +bindkey -M emacs "^[[C" forward-char +bindkey -M emacs "^[F" forward-word +bindkey -M emacs "^[f" forward-word +bindkey -M emacs "^[c" fzf-cd-widget +bindkey -M emacs "^T" fzf-file-widget +bindkey -M emacs "^[G" get-line +bindkey -M emacs "^[g" get-line +bindkey -M emacs "^Xr" history-incremental-search-backward +bindkey -M emacs "^S" history-incremental-search-forward +bindkey -M emacs "^Xs" history-incremental-search-forward +bindkey -M emacs "^[P" history-search-backward +bindkey -M emacs "^[p" history-search-backward +bindkey -M emacs "^[N" history-search-forward +bindkey -M emacs "^[n" history-search-forward +bindkey -M emacs "^X^N" infer-next-history +bindkey -M emacs "^[." insert-last-word +bindkey -M emacs "^[_" insert-last-word +bindkey -M emacs "^X^K" kill-buffer +bindkey -M emacs "^K" kill-line +bindkey -M emacs "^U" kill-whole-line +bindkey -M emacs "^[D" kill-word +bindkey -M emacs "^[d" kill-word +bindkey -M emacs "^[^D" list-choices +bindkey -M emacs "^XG" list-expand +bindkey -M emacs "^Xg" list-expand +bindkey -M emacs "^[-" neg-argument +bindkey -M emacs "^X^O" overwrite-mode +bindkey -M emacs "^Q" push-line +bindkey -M emacs "^[Q" push-line +bindkey -M emacs "^[q" push-line +bindkey -M emacs "^['" quote-line +bindkey -M emacs "^[\"" quote-region +bindkey -M emacs "^V" quoted-insert +bindkey -M emacs "^[H" run-help +bindkey -M emacs "^[h" run-help +bindkey -R -M emacs " "-"~" self-insert +bindkey -R -M emacs "\M-^@"-"\M-^?" self-insert +bindkey -M emacs "^[^I" self-insert-unmeta +bindkey -M emacs "^[^J" self-insert-unmeta +bindkey -M emacs "^[^M" self-insert-unmeta +bindkey -M emacs "^G" send-break +bindkey -M emacs "^[^G" send-break +bindkey -M emacs "^@" set-mark-command +bindkey -M emacs "^[S" spell-word +bindkey -M emacs "^[\$" spell-word +bindkey -M emacs "^[s" spell-word +bindkey -M emacs "^[T" transpose-words +bindkey -M emacs "^[t" transpose-words +bindkey -M emacs "^X^U" undo +bindkey -M emacs "^Xu" undo +bindkey -M emacs "^_" undo +bindkey -M emacs "^[U" up-case-word +bindkey -M emacs "^[u" up-case-word +bindkey -M emacs "^P" up-line-or-history +bindkey -M emacs "^X^V" vi-cmd-mode +bindkey -M emacs "^X^F" vi-find-next-char +bindkey -M emacs "^[|" vi-goto-column +bindkey -M emacs "^X^J" vi-join +bindkey -M emacs "^X^B" vi-match-bracket +bindkey -M emacs "^X=" what-cursor-position +bindkey -M emacs "^[?" which-command +bindkey -M emacs "^Y" yank +bindkey -M emacs "^[y" yank-pop diff --git a/modules/by-name/zs/zsh/config/keymaps/isearch.zsh b/modules/by-name/zs/zsh/config/keymaps/isearch.zsh new file mode 100644 index 00000000..db80bae8 --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps/isearch.zsh @@ -0,0 +1,2 @@ +# Nothing? +bindkey -N isearch diff --git a/modules/by-name/zs/zsh/config/keymaps/vicmd.zsh b/modules/by-name/zs/zsh/config/keymaps/vicmd.zsh new file mode 100644 index 00000000..ceb4f348 --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps/vicmd.zsh @@ -0,0 +1,156 @@ +bindkey -N vicmd + +# Bind in string to out string +bindkey -s -M vicmd "gUU" "gUgU" +bindkey -s -M vicmd "guu" "gugu" +bindkey -s -M vicmd "g~~" "g~g~" + +# Movement +bindkey -M vicmd "h" vi-backward-char +bindkey -M vicmd "t" history-substring-search-down +bindkey -M vicmd "n" history-substring-search-up +bindkey -M vicmd "s" vi-forward-char + +# Search history +bindkey -M vicmd "/" atuin-up-search-vicmd +bindkey -M vicmd "?" atuin-down-search-vicmd +bindkey -M vicmd "l" vi-repeat-search +bindkey -M vicmd "L" vi-rev-repeat-search + +bindkey -M vicmd "f" vi-find-next-char +bindkey -M vicmd "F" vi-find-prev-char + +# Tell the user that more ESC is not possible +bindkey -M vicmd "^[" beep + + +# > Fetch the history line specified by the numeric argument. +# > This defaults to the current history line (i.e. the one that isn't history yet). +bindkey -M vicmd "G" vi-fetch-history +bindkey -M vicmd "gg" beginning-of-buffer-or-history + +bindkey -M vicmd -R "1"-"9" digit-argument + +bindkey -M vicmd "^L" clear-screen + +bindkey -M vicmd ":" execute-named-cmd + +bindkey -M vicmd "=" list-choices + +bindkey -M vicmd "^V" vi-quoted-insert + +bindkey -M vicmd "#" vi-pound-insert +bindkey -M vicmd "u" undo + + +bindkey -M vicmd "A" vi-add-eol +bindkey -M vicmd "i" vi-insert +bindkey -M vicmd "a" vi-add-next +bindkey -M vicmd "I" vi-insert-bol +bindkey -M vicmd "O" vi-open-line-above +bindkey -M vicmd "o" vi-open-line-below + +bindkey -M vicmd "c" vi-change +bindkey -M vicmd "C" vi-change-eol +bindkey -M vicmd "S" vi-change-whole-line + + +bindkey -M vicmd "b" vi-backward-word +bindkey -M vicmd "ge" vi-backward-word-end +bindkey -M vicmd "B" vi-backward-blank-word +bindkey -M vicmd "gE" vi-backward-blank-word-end + +bindkey -M vicmd "w" vi-forward-word +bindkey -M vicmd "e" vi-forward-word-end +bindkey -M vicmd "W" vi-forward-blank-word +bindkey -M vicmd "E" vi-forward-blank-word-end + + +bindkey -M vicmd "x" vi-delete-char +bindkey -M vicmd "X" vi-backward-delete-char +bindkey -M vicmd "d" vi-delete +bindkey -M vicmd "D" vi-kill-eol + +bindkey -M vicmd "y" vi-yank +bindkey -M vicmd "Y" vi-yank-whole-line +bindkey -M vicmd "p" vi-put-after +bindkey -M vicmd "P" vi-put-before + + +bindkey -M vicmd "~" vi-swap-case +bindkey -M vicmd "g~" vi-oper-swap-case +bindkey -M vicmd "gU" vi-up-case +bindkey -M vicmd "gu" vi-down-case + + +bindkey -M vicmd "\^" vi-first-non-blank +bindkey -M vicmd "\$" vi-end-of-line +bindkey -M vicmd "0" vi-digit-or-beginning-of-line + +bindkey -M vicmd "|" vi-goto-column +bindkey -M vicmd "\`" vi-goto-mark +bindkey -M vicmd "'" vi-goto-mark-line + + +bindkey -M vicmd ">" vi-indent +bindkey -M vicmd "<" vi-unindent + + +bindkey -M vicmd "%" vi-match-bracket + + +bindkey -M vicmd "." vi-repeat-change +bindkey -M vicmd ";" vi-repeat-find +bindkey -M vicmd "," vi-rev-repeat-find + + +bindkey -M vicmd "R" vi-replace +bindkey -M vicmd "r" vi-replace-chars +# bindkey -M vicmd "s" vi-substitute + + +bindkey -M vicmd "\"" vi-set-buffer +bindkey -M vicmd "m" vi-set-mark + + +bindkey -M vicmd "ga" what-cursor-position + +bindkey -M vicmd "V" visual-line-mode +bindkey -M vicmd "v" visual-mode + +# Selection +bindkey -M vicmd "aW" select-a-blank-word +bindkey -M vicmd "aa" select-a-shell-word +bindkey -M vicmd "aw" select-a-word +bindkey -M vicmd "iW" select-in-blank-word +bindkey -M vicmd "ia" select-in-shell-word +bindkey -M vicmd "iw" select-in-word +bindkey -M vicmd "a(" select-bracketed +bindkey -M vicmd "a)" select-bracketed +bindkey -M vicmd "a<" select-bracketed +bindkey -M vicmd "a>" select-bracketed +bindkey -M vicmd "aB" select-bracketed +bindkey -M vicmd "a[" select-bracketed +bindkey -M vicmd "a]" select-bracketed +bindkey -M vicmd "ab" select-bracketed +bindkey -M vicmd "a{" select-bracketed +bindkey -M vicmd "a}" select-bracketed +bindkey -M vicmd "i(" select-bracketed +bindkey -M vicmd "i)" select-bracketed +bindkey -M vicmd "i<" select-bracketed +bindkey -M vicmd "i>" select-bracketed +bindkey -M vicmd "iB" select-bracketed +bindkey -M vicmd "i[" select-bracketed +bindkey -M vicmd "i]" select-bracketed +bindkey -M vicmd "ib" select-bracketed +bindkey -M vicmd "i{" select-bracketed +bindkey -M vicmd "i}" select-bracketed +bindkey -M vicmd "a'" select-quoted +bindkey -M vicmd "a\"" select-quoted +bindkey -M vicmd "a\`" select-quoted +bindkey -M vicmd "i'" select-quoted +bindkey -M vicmd "i\"" select-quoted +bindkey -M vicmd "i\`" select-quoted + +# Support pasted text +bindkey -M vicmd "^[[200~" bracketed-paste diff --git a/modules/by-name/zs/zsh/config/keymaps/viins.zsh b/modules/by-name/zs/zsh/config/keymaps/viins.zsh new file mode 100644 index 00000000..4e76cdec --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps/viins.zsh @@ -0,0 +1,55 @@ +bindkey -N viins + +# Completion Debugging +bindkey -M viins "^[~" _bash_complete-word +bindkey -M viins "^X~" _bash_list-choices +bindkey -M viins "^X?" _complete_debug +bindkey -M viins "^Xh" _complete_help +bindkey -M viins "^Xt" _complete_tag +bindkey -M viins "^XC" _correct_filename +bindkey -M viins "^Xc" _correct_word +bindkey -M viins "^Xa" _expand_alias +bindkey -M viins "^Xe" _expand_word +bindkey -M viins "^Xd" _list_expansions +bindkey -M viins "^Xm" _most_recent_file +bindkey -M viins "^Xn" _next_tags +bindkey -M viins "^X^R" _read_comp +bindkey -M viins "^[," _history-complete-newer +bindkey -M viins "^[/" _history-complete-older + +bindkey -M viins "^J" accept-line +bindkey -M viins "^M" accept-line +bindkey -M viins "^L" clear-screen + +bindkey -M viins "^R" atuin-search-viins +bindkey -M viins "^V" edit-command-line + +bindkey -M viins "^[[A" history-substring-search-up # UP ARROW +bindkey -M viins "^[OA" history-substring-search-up # UP ARROW +bindkey -M viins "^[[B" history-substring-search-down # DOWN ARROW +bindkey -M viins "^[OB" history-substring-search-down # DOWN ARROW + +bindkey -M viins "^[[C" beep # RIGHT ARROW +bindkey -M viins "^[OC" beep # RIGHT ARROW +bindkey -M viins "^[[D" beep # LEFT ARROW +bindkey -M viins "^[OD" beep # LEFT ARROW + +# Self inserts +bindkey -M viins "^K" self-insert +bindkey -M viins "^S" self-insert +bindkey -R -M viins "\M-^@"-"\M-^?" self-insert +bindkey -R -M viins "^A"-"^C" self-insert +bindkey -R -M viins "^E"-"^F" self-insert +bindkey -R -M viins "^N"-"^P" self-insert +bindkey -R -M viins "^Y"-"^Z" self-insert +bindkey -R -M viins "^\\\\"-"~" self-insert + +bindkey -M viins "^[" vi-cmd-mode # ESC + +# Support pasted text (and other terminal stuff) +bindkey -M viins "^[[200~" bracketed-paste +bindkey -M viins "^[[2~" overwrite-mode +bindkey -M viins "^[[3~" delete-char +bindkey -M viins "^?" vi-backward-delete-char +bindkey -M viins "^[[5~" beginning-of-buffer-or-history +bindkey -M viins "^[[6~" end-of-buffer-or-history diff --git a/modules/by-name/zs/zsh/config/keymaps/viopp.zsh b/modules/by-name/zs/zsh/config/keymaps/viopp.zsh new file mode 100644 index 00000000..8b291d00 --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps/viopp.zsh @@ -0,0 +1,45 @@ +bindkey -N viopp + +bindkey -M viopp "t" down-line +bindkey -M viopp "n" up-line + +bindkey -M viopp "^[" vi-cmd-mode + + +bindkey -M viopp "aW" select-a-blank-word +bindkey -M viopp "aa" select-a-shell-word +bindkey -M viopp "aw" select-a-word + +bindkey -M viopp "iW" select-in-blank-word +bindkey -M viopp "ia" select-in-shell-word +bindkey -M viopp "iw" select-in-word + + +bindkey -M viopp "a(" select-bracketed +bindkey -M viopp "a)" select-bracketed +bindkey -M viopp "a<" select-bracketed +bindkey -M viopp "a>" select-bracketed +bindkey -M viopp "aB" select-bracketed +bindkey -M viopp "a[" select-bracketed +bindkey -M viopp "a]" select-bracketed +bindkey -M viopp "ab" select-bracketed +bindkey -M viopp "a{" select-bracketed +bindkey -M viopp "a}" select-bracketed +bindkey -M viopp "i(" select-bracketed +bindkey -M viopp "i)" select-bracketed +bindkey -M viopp "i<" select-bracketed +bindkey -M viopp "i>" select-bracketed +bindkey -M viopp "iB" select-bracketed +bindkey -M viopp "i[" select-bracketed +bindkey -M viopp "i]" select-bracketed +bindkey -M viopp "ib" select-bracketed +bindkey -M viopp "i{" select-bracketed +bindkey -M viopp "i}" select-bracketed + +bindkey -M viopp "a'" select-quoted +bindkey -M viopp "a\"" select-quoted +bindkey -M viopp "a\`" select-quoted +bindkey -M viopp "i'" select-quoted +bindkey -M viopp "i\"" select-quoted +bindkey -M viopp "i\`" select-quoted + diff --git a/modules/by-name/zs/zsh/config/keymaps/visual.zsh b/modules/by-name/zs/zsh/config/keymaps/visual.zsh new file mode 100644 index 00000000..c09cd578 --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps/visual.zsh @@ -0,0 +1,53 @@ +bindkey -N visual + +bindkey -M visual "^[" deactivate-region + +bindkey -M visual "t" down-line +bindkey -M visual "n" up-line + +bindkey -M visual "o" exchange-point-and-mark +bindkey -M visual "p" put-replace-selection + + +bindkey -M visual "x" vi-delete +bindkey -M visual "u" vi-down-case +bindkey -M visual "~" vi-oper-swap-case +bindkey -M visual "U" vi-up-case + + +bindkey -M visual "aW" select-a-blank-word +bindkey -M visual "aa" select-a-shell-word +bindkey -M visual "aw" select-a-word + +bindkey -M visual "iW" select-in-blank-word +bindkey -M visual "ia" select-in-shell-word +bindkey -M visual "iw" select-in-word + + +bindkey -M visual "a(" select-bracketed +bindkey -M visual "a)" select-bracketed +bindkey -M visual "a<" select-bracketed +bindkey -M visual "a>" select-bracketed +bindkey -M visual "aB" select-bracketed +bindkey -M visual "a[" select-bracketed +bindkey -M visual "a]" select-bracketed +bindkey -M visual "ab" select-bracketed +bindkey -M visual "a{" select-bracketed +bindkey -M visual "a}" select-bracketed +bindkey -M visual "i(" select-bracketed +bindkey -M visual "i)" select-bracketed +bindkey -M visual "i<" select-bracketed +bindkey -M visual "i>" select-bracketed +bindkey -M visual "iB" select-bracketed +bindkey -M visual "i[" select-bracketed +bindkey -M visual "i]" select-bracketed +bindkey -M visual "ib" select-bracketed +bindkey -M visual "i{" select-bracketed +bindkey -M visual "i}" select-bracketed + +bindkey -M visual "a'" select-quoted +bindkey -M visual "a\"" select-quoted +bindkey -M visual "a\`" select-quoted +bindkey -M visual "i'" select-quoted +bindkey -M visual "i\"" select-quoted +bindkey -M visual "i\`" select-quoted diff --git a/modules/by-name/zs/zsh/config/keymaps_end.zsh b/modules/by-name/zs/zsh/config/keymaps_end.zsh new file mode 100644 index 00000000..2e973de4 --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps_end.zsh @@ -0,0 +1,2 @@ +# Use the vi imitation keymap as default +bindkey -A viins main diff --git a/modules/by-name/zs/zsh/config/keymaps_start.zsh b/modules/by-name/zs/zsh/config/keymaps_start.zsh new file mode 100644 index 00000000..2504e799 --- /dev/null +++ b/modules/by-name/zs/zsh/config/keymaps_start.zsh @@ -0,0 +1,16 @@ +# Delete all default keymaps (with the exception of .safe) +bindkey -D command emacs isearch main vicmd viins viopp visual + +# See https://en.wikipedia.org/wiki/ANSI_escape_code for a explanation of the control +# sequences used in these mappings. +# +# Re-create them with my modifications +# (This is sourced by nix) +# source ./.safe.zsh +# source ./command.zsh +# source ./emacs.zsh +# source ./isearch.zsh +# source ./vicmd.zsh +# source ./viins.zsh +# source ./viopp.zsh +# source ./visual.zsh diff --git a/modules/by-name/zs/zsh/config/zsh-init.zsh b/modules/by-name/zs/zsh/config/zsh-init.zsh index cd8d34a9..aac344dc 100644 --- a/modules/by-name/zs/zsh/config/zsh-init.zsh +++ b/modules/by-name/zs/zsh/config/zsh-init.zsh @@ -1,42 +1,9 @@ #!/usr/bin/env zsh -# If not running interactively, don't do anything -[[ $- != *i* ]] && return -# Flex on the ubuntu users -#[ "$NVIM" ] || hyfetch -[ "$NVIM" ] || task next -#loginctl show-session $XDG_SESSION_ID - -## Enable colors and change prompt: -#autoload -Uz colors && colors -#autoload -Uz compinit && compinit -u -## Edit line in vim buffer ctrl-v -autoload -Uz edit-command-line -zle -N edit-command-line -## Enter vim buffer from normal mode -#autoload -Uz edit-command-line && zle -N edit-command-line -bindkey "^V" edit-command-line +# Display current tasks +[ -z "$NVIM" ] && task next ## zstyles #zstyle ':completion:*' menu select ## Auto complete with case insensitivity #zstyle ':completion:*' matcher-list '' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*' - -#zmodload zsh/complist -#fpath+=/home/dt/.config/zsh/comp -#compinit -#_comp_options+=(globdots) # Include hidden files. -# -## Source configs -#source "${ZDOTDIR}/ali.sh" -#source "${ZDOTDIR}/prompt.sh" -#source "${ZDOTDIR}/hotkeys.sh" -#source "./${path_custom_cursor}" -#source ~/.local/lib/shell/lib -# -## Load zsh-syntax-highlighting -#source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh -## Suggest aliases for commands -#source /usr/share/zsh/plugins/zsh-you-should-use/you-should-use.plugin.zsh -# -##eval "$(lua ~/scripts/z.lua --init zsh enhanced)" diff --git a/modules/by-name/zs/zsh/module.nix b/modules/by-name/zs/zsh/module.nix index 98e0d28a..833da126 100644 --- a/modules/by-name/zs/zsh/module.nix +++ b/modules/by-name/zs/zsh/module.nix @@ -1,6 +1,5 @@ { config, - pkgs, lib, shell_library, system, @@ -8,6 +7,8 @@ }: let cfg = config.soispha.programs.zsh; homeConfig = config.home-manager.users.soispha; + + sourceFile = path: "source ${path}\n"; in { options.soispha.programs.zsh = { enable = lib.mkEnableOption "zsh"; @@ -19,7 +20,10 @@ in { programs.zsh = { enable = true; enableCompletion = true; - autosuggestion.enable = true; + autosuggestion = { + enable = true; + strategy = []; + }; syntaxHighlighting.enable = true; autocd = true; @@ -28,66 +32,80 @@ in { # Thus no `${homeConfig.xdg.configHome}` dotDir = ".config/zsh"; + # TODO: Remove the whole history and replace it completely with `atuin` <2024-10-21> history = { - extended = true; - ignoreDups = false; - expireDuplicatesFirst = false; - ignoreSpace = false; - - path = "${homeConfig.xdg.dataHome}/zsh/history"; - save = 9000000; # number of lines to save - size = 9000000; # number of lines to keep - share = false; # share between sessions - }; - historySubstringSearch = { - enable = true; - searchDownKey = "^[[B"; # DOWN Arrow key - searchUpKey = "^[[A"; # UP Arrow key + path = "/dev/null"; + # save = 0; # number of lines to save + # size = 0; # number of lines to keep + # share = false; # share between sessions }; loginExtra = - "setopt " # The extra space is important - + lib.concatStringsSep "\nsetopt " [ - "AUTO_CD" - "AUTO_PUSHD" - "CHASE_DOTS" + # bash + '' + setopt AUTO_CD + setopt AUTO_PUSHD + setopt CHASE_DOTS - "ALWAYS_TO_END" + setopt ALWAYS_TO_END - "EXTENDED_HISTORY" - "HIST_ALLOW_CLOBBER" - "HIST_VERIFY" - "HIST_FCNTL_LOCK" - "APPEND_HISTORY" + setopt EXTENDED_HISTORY + setopt HIST_ALLOW_CLOBBER + setopt HIST_VERIFY + setopt HIST_FCNTL_LOCK + setopt APPEND_HISTORY - "DVORAK" - "CORRECT" + setopt DVORAK + setopt CORRECT - "PROMPT_SUBST" - "TRANSIENT_RPROMPT" # maybe? + setopt PROMPT_SUBST + setopt TRANSIENT_RPROMPT # maybe? - "COMBINING_CHARS" - "VI" - ]; + setopt COMBINING_CHARS + setopt VI + ''; initExtraFirst = - builtins.readFile ./config/zsh-init.zsh + sourceFile ./config/zsh-init.zsh + '' SHELL_LIBRARY_VERSION="2.1.2" source ${shell_library.rawLib.${system}} - # This next line buffers the first line of the following item: + ''; + + initExtra = let + start = lib.modules.mkBefore ( + # NOTE: This must be before the insult, as we otherwise override the previous handler <2024-02-28> + sourceFile ./config/command_not_found/command_not_found.sh + + sourceFile ./config/command_not_found/command_not_found_insult.sh + + sourceFile ./config/custom_cursor.zsh + + sourceFile ./config/edit_command_line.zsh + + sourceFile ./plugins/zsh-history-substring-search.zsh + ); + end = lib.modules.mkAfter ( + sourceFile ./config/keymaps_start.zsh + + sourceFile ./config/keymaps/command.zsh + + sourceFile ./config/keymaps/emacs.zsh + + sourceFile ./config/keymaps/isearch.zsh + + sourceFile ./config/keymaps/vicmd.zsh + + sourceFile ./config/keymaps/viins.zsh + + sourceFile ./config/keymaps/viopp.zsh + + sourceFile ./config/keymaps/visual.zsh + + sourceFile ./config/keymaps_end.zsh + ); + in + lib.modules.mkMerge + [ + start + end + ]; - '' - # NOTE: This must be before the insult, as we otherwise override the previous handler <2024-02-28> - + builtins.readFile ./config/command_not_found.sh - + builtins.readFile ./config/command_not_found_insult.sh - + builtins.readFile ./config/custom_cursor.zsh - + builtins.readFile "${pkgs.fzf}/share/fzf/key-bindings.zsh"; + localVariables = { + HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND = "bg=cyan,fg=white"; + HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND = "fg=red,underline,standout,bold"; + }; shellAliases = { ll = ". ll"; lm = ". lm"; - - hisea = "history 0 | grep"; }; }; }; diff --git a/modules/by-name/zs/zsh/plugins/zsh-history-substring-search.zsh b/modules/by-name/zs/zsh/plugins/zsh-history-substring-search.zsh new file mode 100644 index 00000000..4314b784 --- /dev/null +++ b/modules/by-name/zs/zsh/plugins/zsh-history-substring-search.zsh @@ -0,0 +1,648 @@ +#!/usr/bin/env zsh +############################################################################## +# Original Source before 2024 modifications: +# https://github.com/zsh-users/zsh-history-substring-search/blob/87ce96b1862928d84b1afe7c173316614b30e301/zsh-history-substring-search.zsh +# +# Copyright (c) 2009 Peter Stephenson +# Copyright (c) 2011 Guido van Steen +# Copyright (c) 2011 Suraj N. Kurapati +# Copyright (c) 2011 Sorin Ionescu +# Copyright (c) 2011 Vincent Guerci +# Copyright (c) 2016 Geza Lore +# Copyright (c) 2017 Bengt Brodersen +# Copyright (c) 2024 Benedikt Peetz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# * Neither the name of the FIZSH nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################## + +#----------------------------------------------------------------------------- +# declare global configuration variables +#----------------------------------------------------------------------------- + +: ${HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND='bg=magenta,fg=white,bold'} +: ${HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND='bg=red,fg=white,bold'} +: ${HISTORY_SUBSTRING_SEARCH_MODE='prefix'} + +#----------------------------------------------------------------------------- +# declare internal global variables +#----------------------------------------------------------------------------- + +typeset -g BUFFER MATCH MBEGIN MEND CURSOR +typeset -g _history_substring_search_refresh_display +typeset -g _history_substring_search_query_highlight +typeset -g _history_substring_search_result +typeset -g _history_substring_search_query +typeset -g -a _history_substring_search_query_parts +typeset -g -a _history_substring_search_raw_matches +typeset -g -i _history_substring_search_raw_match_index +typeset -g -a _history_substring_search_matches +typeset -g -i _history_substring_search_match_index +typeset -g -A _history_substring_search_unique_filter +typeset -g -i _history_substring_search_zsh_5_9 + +#----------------------------------------------------------------------------- +# the main ZLE widgets +#----------------------------------------------------------------------------- + +history-substring-search-up() { + _history-substring-search-begin + + _history-substring-search-up-history || + _history-substring-search-up-buffer || + _history-substring-search-up-search + + _history-substring-search-end +} + +history-substring-search-down() { + _history-substring-search-begin + + _history-substring-search-down-history || + _history-substring-search-down-buffer || + _history-substring-search-down-search + + _history-substring-search-end +} + +zle -N history-substring-search-up +zle -N history-substring-search-down + +#----------------------------------------------------------------------------- +# implementation details +#----------------------------------------------------------------------------- + +zmodload -F zsh/parameter +autoload -Uz is-at-least + +if is-at-least 5.9 $ZSH_VERSION; then + _history_substring_search_zsh_5_9=1 +fi + +# +# We have to check, that the zsh-syntax-highlighting +# plugin has been loaded: +# +# https://github.com/nicoulaj/zsh-syntax-highlighting +# +if [ "$+functions[_zsh_highlight]" -eq 0 ]; then + # zsh-syntax-highlight not found. + # But it should exist because I've loaded it. + : "TODO: we're just assuming it's there." +fi + +_history-substring-search-begin() { + setopt localoptions extendedglob + + _history_substring_search_refresh_display= + _history_substring_search_query_highlight= + + # + # If the buffer is the same as the previously displayed history substring + # search result, then just keep stepping through the match list. Otherwise + # start a new search. + # + if [ -n "$BUFFER" ] && [ "$BUFFER" = "${_history_substring_search_result:-}" ]; then + return; + fi + + # + # Clear the previous result. + # + _history_substring_search_result='' + + if [ -z "$BUFFER" ]; then + # + # If the buffer is empty, we will just act like up-history/down-history + # in ZSH, so we do not need to actually search the history. This should + # speed things up a little. + # + _history_substring_search_query= + _history_substring_search_query_parts=() + _history_substring_search_raw_matches=() + + else + # + # For the purpose of highlighting we keep a copy of the original + # query string. + # + _history_substring_search_query="$BUFFER" + + # + # Compose search pattern, by putting the query into the parts array + # + _history_substring_search_query_parts=(${==_history_substring_search_query}) + + # + # Escape and join query parts with wildcard character '*' as separator + # `(j:CHAR:)` join array to string with CHAR as separator + # + local search_pattern="${(j:*:)_history_substring_search_query_parts[@]//(#m)[\][()|\\*?#<>~^]/\\$MATCH}*" + + # + # Find all occurrences of the search pattern in the history file. + # + _history_substring_search_raw_matches=( + "${(f)$(ATUIN_QUERY="$search_pattern" atuin search --cmd-only --reverse --search-mode "$HISTORY_SUBSTRING_SEARCH_MODE")}" + ) + fi + + # + # In order to stay as responsive as possible, we will process the raw + # matches lazily (when the user requests the next match) to choose items + # that need to be displayed to the user. + # _history_substring_search_raw_match_index holds the index of the last + # unprocessed entry in _history_substring_search_raw_matches. Any items + # that need to be displayed will be added to + # _history_substring_search_matches. + # + # We use an associative array (_history_substring_search_unique_filter) as + # a 'set' data structure to ensure uniqueness of the results if desired. + # If an entry (key) is in the set (non-empty value), then we have already + # added that entry to _history_substring_search_matches. + # + _history_substring_search_raw_match_index=0 + _history_substring_search_matches=() + _history_substring_search_unique_filter=() + + # + # If $_history_substring_search_match_index is equal to + # $#_history_substring_search_matches + 1, this indicates that we + # are beyond the end of $_history_substring_search_matches and that we + # have also processed all entries in + # _history_substring_search_raw_matches. + # + # If $#_history_substring_search_match_index is equal to 0, this indicates + # that we are beyond the beginning of $_history_substring_search_matches. + # + # If we have initially pressed "up" we have to initialize + # $_history_substring_search_match_index to 0 so that it will be + # incremented to 1. + # + # If we have initially pressed "down" we have to initialize + # $_history_substring_search_match_index to 1 so that it will be + # decremented to 0. + # + if [ "$WIDGET" = history-substring-search-down ]; then + _history_substring_search_match_index=1 + else + _history_substring_search_match_index=0 + fi +} + +_history-substring-search-end() { + setopt localoptions extendedglob + + local highlight_memo= + _history_substring_search_result="$BUFFER" + + if [ "$_history_substring_search_zsh_5_9" -eq 1 ]; then + highlight_memo='memo=history-substring-search' + fi + + # the search was successful so display the result properly by clearing away + # existing highlights and moving the cursor to the end of the result buffer + if [ "$_history_substring_search_refresh_display" -eq 1 ]; then + if [ -n "$highlight_memo" ]; then + region_highlight=( "${(@)region_highlight:#*${highlight_memo}*}" ) + else + region_highlight=() + fi + CURSOR="${#BUFFER}" + fi + + # highlight command line using zsh-syntax-highlighting + _zsh_highlight + + # highlight the search query inside the command line + if [ -n "$_history_substring_search_query_highlight" ]; then + # highlight first matching query parts + local highlight_start_index=0 + local highlight_end_index=0 + local query_part + + for query_part in "$_history_substring_search_query_parts[@]"; do + local escaped_query_part="${query_part//(#m)[\][()|\\*?#<>~^]/\\$MATCH}" + + # (i) get index of pattern + local query_part_match_index="${${BUFFER:$highlight_start_index}[(i)${escaped_query_part}]}" + + if [ "$query_part_match_index" -le "${#BUFFER:$highlight_start_index}" ]; then + highlight_start_index=$(( highlight_start_index + query_part_match_index )) + highlight_end_index=$(( highlight_start_index + ${#query_part} )) + + region_highlight+=( + "$(($highlight_start_index - 1)) $(($highlight_end_index - 1)) ${_history_substring_search_query_highlight}${highlight_memo:+,$highlight_memo}" + ) + fi + done + fi + + # For debugging purposes: + # zle -R "mn: "$_history_substring_search_match_index" m#: "${#_history_substring_search_matches} + # read -k -t 200 && zle -U -- "$REPLY" + + # + # When this function returns, z-sy-h runs its line-pre-redraw hook. It has no + # logic for determining highlight priority, when two different memo= marked + # region highlights overlap; instead, it always prioritises itself. Below is + # a workaround for dealing with it. + # + if [ "$_history_substring_search_zsh_5_9" -eq 1 ]; then + zle -R + # + # After line redraw with desired highlight, wait for timeout or user input + # before removing search highlight and exiting. This ensures no highlights + # are left lingering after search is finished. + # + read -k -t ${HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_TIMEOUT:-1} && zle -U -- "$REPLY" + region_highlight=( "${(@)region_highlight:#*${highlight_memo}*}" ) + fi + + # Exit successfully from the history-substring-search-* widgets. + return 0 +} + +_history-substring-search-up-buffer() { + # + # Check if the UP arrow was pressed to move the cursor within a multi-line + # buffer. This amounts to three tests: + # + # 1. $#buflines -gt 1. + # + # 2. $CURSOR -ne $#BUFFER. + # + # 3. Check if we are on the first line of the current multi-line buffer. + # If so, pressing UP would amount to leaving the multi-line buffer. + # + # We check this by adding an extra "x" to $LBUFFER, which makes + # sure that xlbuflines is always equal to the number of lines + # until $CURSOR (including the line with the cursor on it). + # + local buflines XLBUFFER xlbuflines + buflines=(${(f)BUFFER}) + XLBUFFER=$LBUFFER"x" + xlbuflines=(${(f)XLBUFFER}) + + if [ "$#buflines" -gt 1 ] && ["$CURSOR" -ne "$#BUFFER" ] && [ "$#xlbuflines" -ne 1 ]; then + zle up-line-or-history + return 0 + fi + + return 1 +} + +_history-substring-search-down-buffer() { + # + # Check if the DOWN arrow was pressed to move the cursor within a multi-line + # buffer. This amounts to three tests: + # + # 1. $#buflines -gt 1. + # + # 2. $CURSOR -ne $#BUFFER. + # + # 3. Check if we are on the last line of the current multi-line buffer. + # If so, pressing DOWN would amount to leaving the multi-line buffer. + # + # We check this by adding an extra "x" to $RBUFFER, which makes + # sure that xrbuflines is always equal to the number of lines + # from $CURSOR (including the line with the cursor on it). + # + local buflines XRBUFFER xrbuflines + buflines=(${(f)BUFFER}) + XRBUFFER="x"$RBUFFER + xrbuflines=(${(f)XRBUFFER}) + + if [ "$#buflines" -gt 1 ] && [ "$CURSOR" -ne "$#BUFFER" ] && [ "$#xrbuflines" -ne 1 ]; then + zle down-line-or-history + return 0 + fi + + return 1 +} + +_history-substring-search-up-history() { + # + # Behave like up in ZSH, except clear the $BUFFER + # when beginning of history is reached like in Fish. + # + if [ -z "$_history_substring_search_query" ]; then + # we have reached the absolute top of history + if [ "$HISTNO" -eq 1 ]; then + BUFFER="" + + # going up from somewhere below the top of history + else + zle up-line-or-history + fi + + return 0 + fi + + return 1 +} + +_history-substring-search-down-history() { + # + # Behave like down-history in ZSH, except clear the + # $BUFFER when end of history is reached like in Fish. + # + if [ -z $_history_substring_search_query ]; then + + # going down from the absolute top of history + if [ "$HISTNO" -eq 1 ] && [ -z "$BUFFER" ]; then + # BUFFER=${history[1]} + BUFFER="$(atuin history list --cmd-only --reverse false | tail -n 1)" + _history_substring_search_refresh_display=1 + + # going down from somewhere above the bottom of history + else + zle down-line-or-history + fi + + return 0 + fi + + return 1 +} + +_history_substring_search_process_raw_matches() { + # + # Process more outstanding raw matches and append any matches that need to + # be displayed to the user to _history_substring_search_matches. + # Return whether there were any more results appended. + # + + # + # While we have more raw matches. Process them to see if there are any more + # matches that need to be displayed to the user. + # + if [ "$_history_substring_search_raw_match_index" -lt "$#_history_substring_search_raw_matches" ]; then + # + # Move on to the next raw entry and get its history index. + # + _history_substring_search_raw_match_index+=1 + local entry="${_history_substring_search_raw_matches[$_history_substring_search_raw_match_index]}" + + + if [ -z "$entry" ]; then + # + # The match was empty (We did not find another match.) + # Communicate that + # + return 1 + + else + # + # Just append the new history index to the processed matches. + # + _history_substring_search_matches+=("$entry") + + # + # Indicate that we did find a match. + # + return 0 + fi + fi + + # + # We are beyond the end of the list of raw matches. Indicate that no + # more matches are available. + # + return 1 +} + +_history-substring-search-has-next() { + # + # Predicate function that returns whether any more older matches are + # available. + # + + if [ "$_history_substring_search_match_index" -lt "$#_history_substring_search_matches" ]; then + # + # We did not reach the end of the processed list, so we do have further + # matches. + # + return 0 + + else + # + # We are at the end of the processed list. Try to process further + # unprocessed matches. _history_substring_search_process_raw_matches + # returns whether any more matches were available, so just return + # that result. + # + _history_substring_search_process_raw_matches + return $? + fi +} + +_history-substring-search-has-prev() { + # + # Predicate function that returns whether any more younger matches are + # available. + # + + if [ "$_history_substring_search_match_index" -gt 1 ]; then + # + # We did not reach the beginning of the processed list, so we do have + # further matches. + # + return 0 + + else + # + # We are at the beginning of the processed list. We do not have any more + # matches. + # + return 1 + fi +} + +_history-substring-search-found() { + # + # A match is available. The index of the match is held in + # $_history_substring_search_match_index + # + # 1. Make $BUFFER equal to the matching history entry. + # + # 2. Use $HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND + # to highlight the current buffer. + # + BUFFER="$_history_substring_search_matches[$_history_substring_search_match_index]" + _history_substring_search_query_highlight="$HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND" +} + +_history-substring-search-not-found() { + # + # No more matches are available. + # + # 1. Make $BUFFER equal to $_history_substring_search_query so the user can + # revise it and search again. + # + # 2. Use $HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND + # to highlight the current buffer. + # + BUFFER="$_history_substring_search_query" + _history_substring_search_query_highlight="$HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND" +} + +_history-substring-search-up-search() { + _history_substring_search_refresh_display=1 + + # + # Select history entry during history-substring-down-search: + # + # The following variables have been initialized in + # _history-substring-search-begin(): + # + # $_history_substring_search_matches is the current list of matches that + # need to be displayed to the user. + # $_history_substring_search_match_index is the index of the current match + # that is being displayed to the user. + # + # The range of values that $_history_substring_search_match_index can take + # is: [0, $#_history_substring_search_matches + 1]. A value of 0 + # indicates that we are beyond the beginning of + # $_history_substring_search_matches. A value of + # $#_history_substring_search_matches + 1 indicates that we are beyond + # the end of $_history_substring_search_matches and that we have also + # processed all entries in _history_substring_search_raw_matches. + # + # If $_history_substring_search_match_index equals + # $#_history_substring_search_matches and + # $_history_substring_search_raw_match_index is not greater than + # $#_history_substring_search_raw_matches, then we need to further process + # $_history_substring_search_raw_matches to see if there are any more + # entries that need to be displayed to the user. + # + # In _history-substring-search-up-search() the initial value of + # $_history_substring_search_match_index is 0. This value is set in + # _history-substring-search-begin(). _history-substring-search-up-search() + # will initially increment it to 1. + # + + if [ "$_history_substring_search_match_index" -gt "$#_history_substring_search_matches" ]; then + # + # We are beyond the end of $_history_substring_search_matches. This + # can only happen if we have also exhausted the unprocessed matches in + # _history_substring_search_raw_matches. + # + # 1. Update display to indicate search not found. + # + _history-substring-search-not-found + return + fi + + if _history-substring-search-has-next; then + # + # We do have older matches. + # + # 1. Move index to point to the next match. + # 2. Update display to indicate search found. + # + _history_substring_search_match_index+=1 + _history-substring-search-found + + else + # + # We do not have older matches. + # + # 1. Move the index beyond the end of + # _history_substring_search_matches. + # 2. Update display to indicate search not found. + # + _history_substring_search_match_index+=1 + _history-substring-search-not-found + fi +} + +_history-substring-search-down-search() { + _history_substring_search_refresh_display=1 + + # + # Select history entry during history-substring-down-search: + # + # The following variables have been initialized in + # _history-substring-search-up/down-search(): + # + # $_history_substring_search_matches is the current list of matches that + # need to be displayed to the user. + # $_history_substring_search_match_index is the index of the current match + # that is being displayed to the user. + # + # The range of values that $_history_substring_search_match_index can take + # is: [0, $#_history_substring_search_matches + 1]. A value of 0 + # indicates that we are beyond the beginning of + # $_history_substring_search_matches. A value of + # $#_history_substring_search_matches + 1 indicates that we are beyond + # the end of $_history_substring_search_matches and that we have also + # processed all entries in _history_substring_search_raw_matches. + # + # In _history-substring-search-down-search() the initial value of + # $_history_substring_search_match_index is 1. This value is set in + # _history-substring-search-begin(). _history-substring-search-down-search() + # will initially decrement it to 0. + # + + if [ "$_history_substring_search_match_index" -lt 1 ]; then + # + # We are beyond the beginning of $_history_substring_search_matches. + # + # 1. Update display to indicate search not found. + # + _history-substring-search-not-found + return + fi + + if _history-substring-search-has-prev; then + # + # We do have younger matches. + # + # 1. Move index to point to the previous match. + # 2. Update display to indicate search found. + # + _history_substring_search_match_index+=-1 + _history-substring-search-found + + else + # + # We do not have younger matches. + # + # 1. Move the index beyond the beginning of + # _history_substring_search_matches. + # 2. Update display to indicate search not found. + # + _history_substring_search_match_index+=-1 + _history-substring-search-not-found + fi +} + +# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- +# vim: ft=zsh sw=2 ts=2 et -- cgit 1.4.1