From 9b9ce3155088f105b98ee77d3ff3897407044559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Mon, 17 Jun 2013 19:26:21 +0200 Subject: [PATCH 01/25] Fix variable name --- share/functions/__fish_git_prompt.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index 5c528beae..407edc48c 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -199,7 +199,7 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi case "* 0" # behind upstream echo " $___fish_git_prompt_char_upstream_behind$behind" case '*' # diverged from upstream - echo " $__fish_git_prompt_char_upstream_diverged$ahead-$behind" + echo " $___fish_git_prompt_char_upstream_diverged$ahead-$behind" end end end From 1debe4f055cd4d6c61b6a21a080cd33234b22fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Mon, 17 Jun 2013 19:29:34 +0200 Subject: [PATCH 02/25] Informative version of __fish_git_prompt_show_upstream --- share/functions/__fish_git_prompt.fish | 67 +++++++++++++++++--------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index 407edc48c..c6bd511f2 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -82,6 +82,7 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi set -l upstream git set -l legacy set -l verbose + set -l informative set -l svn_url_pattern set -l show_upstream $__fish_git_prompt_showupstream git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showUpstream)$' ^/dev/null | tr '\0\n' '\n ' | while read -l key value @@ -109,6 +110,8 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi set upstream $option case verbose set verbose 1 + case informative + set informative 1 case legacy set legacy 1 end @@ -176,31 +179,44 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi end # calculate the result - if test -z "$verbose" - switch "$count" - case '' # no upstream - case "0 0" # equal to upstream - echo $___fish_git_prompt_char_upstream_equal - case "0 *" # ahead of upstream - echo $___fish_git_prompt_char_upstream_ahead - case "* 0" # behind upstream - echo $___fish_git_prompt_char_upstream_behind - case '*' # diverged from upstream - echo $___fish_git_prompt_char_upstream_diverged - end + if test -n "$verbose" + echo $count | read -l behind ahead + switch "$count" + case '' # no upstream + case "0 0" # equal to upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" + case "0 *" # ahead of upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" + case "* 0" # behind upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" + case '*' # diverged from upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind" + end + else if test -n informative + echo $count | read -l behind ahead + switch "$count" + case '' # no upstream + case "0 0" # equal to upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" + case "0 *" # ahead of upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" + case "* 0" # behind upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" + case '*' # diverged from upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead$___fish_git_prompt_char_upstream_behind$behind" + end else - echo $count | read -l behind ahead - switch "$count" - case '' # no upstream - case "0 0" # equal to upstream - echo " $___fish_git_prompt_char_upstream_equal" - case "0 *" # ahead of upstream - echo " $___fish_git_prompt_char_upstream_ahead$ahead" - case "* 0" # behind upstream - echo " $___fish_git_prompt_char_upstream_behind$behind" - case '*' # diverged from upstream - echo " $___fish_git_prompt_char_upstream_diverged$ahead-$behind" - end + switch "$count" + case '' # no upstream + case "0 0" # equal to upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" + case "0 *" # ahead of upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" + case "* 0" # behind upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" + case '*' # diverged from upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind" + end end end @@ -416,6 +432,9 @@ function __fish_git_prompt_validate_chars --description "__fish_git_prompt helpe if not set -q ___fish_git_prompt_char_upstream_diverged set -g ___fish_git_prompt_char_upstream_diverged (set -q __fish_git_prompt_char_upstream_diverged; and echo $__fish_git_prompt_char_upstream_diverged; or echo '<>') end + if not set -q ___fish_git_prompt_char_upstream_prefix + set -g ___fish_git_prompt_char_upstream_prefix (set -q __fish_git_prompt_char_upstream_prefix; and echo $__fish_git_prompt_char_upstream_prefix; or echo ' ') + end end function __fish_git_prompt_validate_colors --description "__fish_git_prompt helper, checks color variables" From c95537997148a840ad5ee6df240fae39d8c25ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Mon, 17 Jun 2013 22:20:56 +0200 Subject: [PATCH 03/25] Added informative status method --- share/functions/__fish_git_prompt.fish | 57 ++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index c6bd511f2..a8dee72d9 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -75,6 +75,8 @@ # 'upstream_equal', 'upstream_behind', 'upstream_ahead', and # 'upstream_diverged'. +set -g ___fish_git_prompt_status_order stagedstate invalidstate dirtystate untrackedfiles + function __fish_git_prompt_show_upstream --description "Helper function for __fish_git_prompt" # Ask git-config for some config options set -l svn_remote @@ -326,6 +328,49 @@ function __fish_git_prompt_dirty --description "__fish_git_prompt helper, tells echo $dirty end +function __fish_git_prompt_status_info + + set -l changedFiles (git diff --name-status | cut -c 1-2) + set -l stagedFiles (git diff --staged --name-status | cut -c 1-2) + + set -l dirtystate (math (count $changedFiles) - (count (echo $changedFiles | grep "U"))) + set -l invalidstate (count (echo $stagedFiles | grep "U")) + set -l stagedstate (math (count $stagedFiles) - $invalidstate) + set -l untrackedfiles (count (git ls-files --others --exclude-standard)) + + set -l info + + __fish_git_prompt_validate_colors + __fish_git_prompt_validate_chars + + if [ (math $dirtystate + $invalidstate + $stagedstate + $untrackedfiles) = 0 ] + set git_status $___fish_git_prompt_color_cleanstate$___fish_git_prompt_char_cleanstate$___fish_git_prompt_color_cleanstate_done + else + for i in $___fish_git_prompt_status_order + if [ $$i != "0" ] + set -l color_var ___fish_git_prompt_color_$i + set -l color_done_var ___fish_git_prompt_color_$i + set -l symbol_var ___fish_git_prompt_char_$i + + set -l color $$color_var + set -l color_done $$color_done_var + set -l symbol $$symbol_var + + set -l count + + if not set -q __fish_git_prompt_hide_$i + set count $$i + end + + set info "$info$color$symbol$count$color_done" + end + end + end + + echo $info + +end + function __fish_git_prompt_current_branch_bare --description "__fish_git_prompt helper, tells wheter or not the current branch is bare" set -l bare @@ -405,6 +450,9 @@ function __fish_git_prompt_git_dir --description "__fish_git_prompt helper, retu end function __fish_git_prompt_validate_chars --description "__fish_git_prompt helper, checks char variables" + if not set -q ___fish_git_prompt_char_cleanstate + set -g ___fish_git_prompt_char_cleanstate (set -q __fish_git_prompt_char_cleanstate; and echo $__fish_git_prompt_char_cleanstate; or echo '.') + end if not set -q ___fish_git_prompt_char_dirtystate set -g ___fish_git_prompt_char_dirtystate (set -q __fish_git_prompt_char_dirtystate; and echo $__fish_git_prompt_char_dirtystate; or echo '*') end @@ -492,6 +540,15 @@ function __fish_git_prompt_validate_colors --description "__fish_git_prompt help set -g ___fish_git_prompt_color_branch_done $___fish_git_prompt_color_done end end + if not set -q ___fish_git_prompt_color_cleanstate + if test -n "$__fish_git_prompt_color_cleanstate" + set -g ___fish_git_prompt_color_cleanstate (set_color $__fish_git_prompt_color_cleanstate) + set -g ___fish_git_prompt_color_cleanstate_done (set_color normal) + else + set -g ___fish_git_prompt_color_cleanstate $___fish_git_prompt_color + set -g ___fish_git_prompt_color_cleanstate_done $___fish_git_prompt_color_done + end + end if not set -q ___fish_git_prompt_color_dirtystate if test -n "$__fish_git_prompt_color_dirtystate" set -g ___fish_git_prompt_color_dirtystate (set_color $__fish_git_prompt_color_dirtystate) From 1e415a9943586b707e0cb7792ac61bf3781d197a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Mon, 17 Jun 2013 23:06:05 +0200 Subject: [PATCH 04/25] Fixes, new method added to prompt --- share/functions/__fish_git_prompt.fish | 42 +++++++++++++++----------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index a8dee72d9..3f95dd17b 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -199,7 +199,6 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi switch "$count" case '' # no upstream case "0 0" # equal to upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" case "0 *" # ahead of upstream echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" case "* 0" # behind upstream @@ -234,32 +233,39 @@ function __fish_git_prompt --description "Prompt function for Git" set -l u #untracked set -l c (__fish_git_prompt_current_branch_bare) set -l p #upstream + set -l status_info __fish_git_prompt_validate_chars if test "true" = (git rev-parse --is-inside-work-tree ^/dev/null) - if test -n "$__fish_git_prompt_showdirtystate" - set -l config (git config --bool bash.showDirtyState) - if test "$config" != "false" - set w (__fish_git_prompt_dirty) - set i (__fish_git_prompt_staged) - end - end - if test -n "$__fish_git_prompt_showstashstate" - git rev-parse --verify refs/stash >/dev/null ^&1; and set s $___fish_git_prompt_char_stashstate - end + if test -n "$__fish_git_prompt_show_status" + set status_info "|"(__fish_git_prompt_status_info) + else + if test -n "$__fish_git_prompt_showdirtystate" + set -l config (git config --bool bash.showDirtyState) + if test "$config" != "false" + set w (__fish_git_prompt_dirty) + set i (__fish_git_prompt_staged) + end + end - if test -n "$__fish_git_prompt_showuntrackedfiles" - set -l files (git ls-files --others --exclude-standard) - if test -n "$files" - set u $___fish_git_prompt_char_untrackedfiles - end + if test -n "$__fish_git_prompt_showstashstate" + git rev-parse --verify refs/stash >/dev/null ^&1; and set s $___fish_git_prompt_char_stashstate + end + + if test -n "$__fish_git_prompt_showuntrackedfiles" + set -l files (git ls-files --others --exclude-standard) + if test -n "$files" + set u $___fish_git_prompt_char_untrackedfiles + end + end end if test -n "$__fish_git_prompt_showupstream" set p (__fish_git_prompt_show_upstream) end + end __fish_git_prompt_validate_colors @@ -300,7 +306,7 @@ function __fish_git_prompt --description "Prompt function for Git" set format " (%s)" end - printf "%s$format%s" "$___fish_git_prompt_color_prefix" "$___fish_git_prompt_color_prefix_done$c$b$f$r$p$___fish_git_prompt_color_suffix" "$___git_ps_color_suffix_done" + printf "%s$format%s" "$___fish_git_prompt_color_prefix" "$___fish_git_prompt_color_prefix_done$c$b$f$r$p$status_info$___fish_git_prompt_color_suffix" "$___git_ps_color_suffix_done" end ### helper functions @@ -344,7 +350,7 @@ function __fish_git_prompt_status_info __fish_git_prompt_validate_chars if [ (math $dirtystate + $invalidstate + $stagedstate + $untrackedfiles) = 0 ] - set git_status $___fish_git_prompt_color_cleanstate$___fish_git_prompt_char_cleanstate$___fish_git_prompt_color_cleanstate_done + set info $___fish_git_prompt_color_cleanstate$___fish_git_prompt_char_cleanstate$___fish_git_prompt_color_cleanstate_done else for i in $___fish_git_prompt_status_order if [ $$i != "0" ] From 918df393e6ebd95d581acc4f9d67002289e82ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Tue, 18 Jun 2013 08:52:32 +0200 Subject: [PATCH 05/25] Use tabs, sample prompt --- share/functions/__fish_git_prompt.fish | 176 +++++++++--------- .../sample_prompts/informative_git.fish | 47 +++++ 2 files changed, 135 insertions(+), 88 deletions(-) create mode 100644 share/tools/web_config/sample_prompts/informative_git.fish diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index 3f95dd17b..0e7ed6f37 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -112,8 +112,8 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi set upstream $option case verbose set verbose 1 - case informative - set informative 1 + case informative + set informative 1 case legacy set legacy 1 end @@ -182,42 +182,42 @@ function __fish_git_prompt_show_upstream --description "Helper function for __fi # calculate the result if test -n "$verbose" - echo $count | read -l behind ahead - switch "$count" - case '' # no upstream - case "0 0" # equal to upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" - case "0 *" # ahead of upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" - case "* 0" # behind upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" - case '*' # diverged from upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind" - end - else if test -n informative - echo $count | read -l behind ahead - switch "$count" - case '' # no upstream - case "0 0" # equal to upstream - case "0 *" # ahead of upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" - case "* 0" # behind upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" - case '*' # diverged from upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead$___fish_git_prompt_char_upstream_behind$behind" - end + echo $count | read -l behind ahead + switch "$count" + case '' # no upstream + case "0 0" # equal to upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" + case "0 *" # ahead of upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" + case "* 0" # behind upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" + case '*' # diverged from upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind" + end + else if test -n informative + echo $count | read -l behind ahead + switch "$count" + case '' # no upstream + case "0 0" # equal to upstream + case "0 *" # ahead of upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" + case "* 0" # behind upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" + case '*' # diverged from upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead$___fish_git_prompt_char_upstream_behind$behind" + end else - switch "$count" - case '' # no upstream - case "0 0" # equal to upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" - case "0 *" # ahead of upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" - case "* 0" # behind upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" - case '*' # diverged from upstream - echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind" - end + switch "$count" + case '' # no upstream + case "0 0" # equal to upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_equal" + case "0 *" # ahead of upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_ahead$ahead" + case "* 0" # behind upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_behind$behind" + case '*' # diverged from upstream + echo "$___fish_git_prompt_char_upstream_prefix$___fish_git_prompt_char_upstream_diverged$ahead-$behind" + end end end @@ -239,27 +239,27 @@ function __fish_git_prompt --description "Prompt function for Git" if test "true" = (git rev-parse --is-inside-work-tree ^/dev/null) - if test -n "$__fish_git_prompt_show_status" - set status_info "|"(__fish_git_prompt_status_info) - else - if test -n "$__fish_git_prompt_showdirtystate" - set -l config (git config --bool bash.showDirtyState) - if test "$config" != "false" - set w (__fish_git_prompt_dirty) - set i (__fish_git_prompt_staged) - end - end + if test -n "$__fish_git_prompt_show_status" + set status_info "|"(__fish_git_prompt_status_info) + else + if test -n "$__fish_git_prompt_showdirtystate" + set -l config (git config --bool bash.showDirtyState) + if test "$config" != "false" + set w (__fish_git_prompt_dirty) + set i (__fish_git_prompt_staged) + end + end - if test -n "$__fish_git_prompt_showstashstate" - git rev-parse --verify refs/stash >/dev/null ^&1; and set s $___fish_git_prompt_char_stashstate - end + if test -n "$__fish_git_prompt_showstashstate" + git rev-parse --verify refs/stash >/dev/null ^&1; and set s $___fish_git_prompt_char_stashstate + end - if test -n "$__fish_git_prompt_showuntrackedfiles" - set -l files (git ls-files --others --exclude-standard) - if test -n "$files" - set u $___fish_git_prompt_char_untrackedfiles - end - end + if test -n "$__fish_git_prompt_showuntrackedfiles" + set -l files (git ls-files --others --exclude-standard) + if test -n "$files" + set u $___fish_git_prompt_char_untrackedfiles + end + end end if test -n "$__fish_git_prompt_showupstream" @@ -336,44 +336,44 @@ end function __fish_git_prompt_status_info - set -l changedFiles (git diff --name-status | cut -c 1-2) - set -l stagedFiles (git diff --staged --name-status | cut -c 1-2) + set -l changedFiles (git diff --name-status | cut -c 1-2) + set -l stagedFiles (git diff --staged --name-status | cut -c 1-2) - set -l dirtystate (math (count $changedFiles) - (count (echo $changedFiles | grep "U"))) - set -l invalidstate (count (echo $stagedFiles | grep "U")) - set -l stagedstate (math (count $stagedFiles) - $invalidstate) - set -l untrackedfiles (count (git ls-files --others --exclude-standard)) + set -l dirtystate (math (count $changedFiles) - (count (echo $changedFiles | grep "U"))) + set -l invalidstate (count (echo $stagedFiles | grep "U")) + set -l stagedstate (math (count $stagedFiles) - $invalidstate) + set -l untrackedfiles (count (git ls-files --others --exclude-standard)) - set -l info + set -l info - __fish_git_prompt_validate_colors - __fish_git_prompt_validate_chars + __fish_git_prompt_validate_colors + __fish_git_prompt_validate_chars - if [ (math $dirtystate + $invalidstate + $stagedstate + $untrackedfiles) = 0 ] - set info $___fish_git_prompt_color_cleanstate$___fish_git_prompt_char_cleanstate$___fish_git_prompt_color_cleanstate_done - else - for i in $___fish_git_prompt_status_order - if [ $$i != "0" ] - set -l color_var ___fish_git_prompt_color_$i - set -l color_done_var ___fish_git_prompt_color_$i - set -l symbol_var ___fish_git_prompt_char_$i + if [ (math $dirtystate + $invalidstate + $stagedstate + $untrackedfiles) = 0 ] + set info $___fish_git_prompt_color_cleanstate$___fish_git_prompt_char_cleanstate$___fish_git_prompt_color_cleanstate_done + else + for i in $___fish_git_prompt_status_order + if [ $$i != "0" ] + set -l color_var ___fish_git_prompt_color_$i + set -l color_done_var ___fish_git_prompt_color_$i + set -l symbol_var ___fish_git_prompt_char_$i - set -l color $$color_var - set -l color_done $$color_done_var - set -l symbol $$symbol_var + set -l color $$color_var + set -l color_done $$color_done_var + set -l symbol $$symbol_var - set -l count + set -l count - if not set -q __fish_git_prompt_hide_$i - set count $$i - end + if not set -q __fish_git_prompt_hide_$i + set count $$i + end - set info "$info$color$symbol$count$color_done" - end - end - end + set info "$info$color$symbol$count$color_done" + end + end + end - echo $info + echo $info end @@ -486,9 +486,9 @@ function __fish_git_prompt_validate_chars --description "__fish_git_prompt helpe if not set -q ___fish_git_prompt_char_upstream_diverged set -g ___fish_git_prompt_char_upstream_diverged (set -q __fish_git_prompt_char_upstream_diverged; and echo $__fish_git_prompt_char_upstream_diverged; or echo '<>') end - if not set -q ___fish_git_prompt_char_upstream_prefix - set -g ___fish_git_prompt_char_upstream_prefix (set -q __fish_git_prompt_char_upstream_prefix; and echo $__fish_git_prompt_char_upstream_prefix; or echo ' ') - end + if not set -q ___fish_git_prompt_char_upstream_prefix + set -g ___fish_git_prompt_char_upstream_prefix (set -q __fish_git_prompt_char_upstream_prefix; and echo $__fish_git_prompt_char_upstream_prefix; or echo ' ') + end end function __fish_git_prompt_validate_colors --description "__fish_git_prompt helper, checks color variables" diff --git a/share/tools/web_config/sample_prompts/informative_git.fish b/share/tools/web_config/sample_prompts/informative_git.fish new file mode 100644 index 000000000..b7bf19f3a --- /dev/null +++ b/share/tools/web_config/sample_prompts/informative_git.fish @@ -0,0 +1,47 @@ +# name: Informative Git Prompt +# author: Mariusz Smykula + +set -g __fish_git_prompt_show_status 1 +set -g __fish_git_prompt_hide_untrackedfiles 1 + +set -g __fish_git_prompt_color_branch magenta +set -g __fish_git_prompt_showupstream "informative" +set -g __fish_git_prompt_char_upstream_ahead "↑" +set -g __fish_git_prompt_char_upstream_behind "↓" +set -g __fish_git_prompt_char_upstream_prefix "" + +set -g __fish_git_prompt_char_stagedstate "●" +set -g __fish_git_prompt_char_dirtystate "✚" +set -g __fish_git_prompt_char_untrackedfiles "…" +set -g __fish_git_prompt_char_conflictedstate "✖" +set -g __fish_git_prompt_char_cleanstate "✔" + +set -g __fish_git_prompt_color_dirtystate blue +set -g __fish_git_prompt_color_stagedstate yellow +set -g __fish_git_prompt_color_invalidstate red +set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal +set -g __fish_git_prompt_color_cleanstate green + + +function fish_prompt --description 'Write out the prompt' + + set -l last_status $status + + if not set -q __fish_prompt_normal + set -g __fish_prompt_normal (set_color normal) + end + + # PWD + set_color $fish_color_cwd + echo -n (prompt_pwd) + set_color normal + + printf '%s ' (__fish_git_prompt) + + if not test $last_status -eq 0 + set_color $fish_color_error + end + + echo -n '$ ' + +end From 47022832800f1b224fe6119a1a793aafaa2a8b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Tue, 18 Jun 2013 21:49:53 +0200 Subject: [PATCH 06/25] Less code is better, __fish_git_prompt_validate_colors refactor --- share/functions/__fish_git_prompt.fish | 150 ++++++------------------- 1 file changed, 33 insertions(+), 117 deletions(-) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index 0e7ed6f37..bef8753c6 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -491,124 +491,40 @@ function __fish_git_prompt_validate_chars --description "__fish_git_prompt helpe end end +function __fish_git_prompt_set_color + set -l user_variable_name "$argv[1]" + set -l variable _$user_variable_name + set -l variable_done "$variable"_done + set -l user_variable $$user_variable_name + + if not set -q $variable + if test -n "$user_variable" + set -g $variable (set_color $user_variable) + set -g $variable_done (set_color normal) + else + set -g $variable '' + set -g $variable_done '' + end + end + +end + function __fish_git_prompt_validate_colors --description "__fish_git_prompt helper, checks color variables" - if not set -q ___fish_git_prompt_color - if test -n "$__fish_git_prompt_color" - set -g ___fish_git_prompt_color (set_color $__fish_git_prompt_color) - set -g ___fish_git_prompt_color_done (set_color normal) - else - set -g ___fish_git_prompt_color '' - set -g ___fish_git_prompt_color_done '' - end - end - if not set -q ___fish_git_prompt_color_prefix - if test -n "$__fish_git_prompt_color_prefix" - set -g ___fish_git_prompt_color_prefix (set_color $__fish_git_prompt_color_prefix) - set -g ___fish_git_prompt_color_prefix_done (set_color normal) - else - set -g ___fish_git_prompt_color_prefix $___fish_git_prompt_color - set -g ___fish_git_prompt_color_prefix_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_suffix - if test -n "$__fish_git_prompt_color_suffix" - set -g ___fish_git_prompt_color_suffix (set_color $__fish_git_prompt_color_suffix) - set -g ___fish_git_prompt_color_suffix_done (set_color normal) - else - set -g ___fish_git_prompt_color_suffix $___fish_git_prompt_color - set -g ___fish_git_prompt_color_suffix_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_bare - if test -n "$__fish_git_prompt_color_bare" - set -g ___fish_git_prompt_color_bare (set_color $__fish_git_prompt_color_bare) - set -g ___fish_git_prompt_color_bare_done (set_color normal) - else - set -g ___fish_git_prompt_color_bare $___fish_git_prompt_color - set -g ___fish_git_prompt_color_bare_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_merging - if test -n "$__fish_git_prompt_color_merging" - set -g ___fish_git_prompt_color_merging (set_color $__fish_git_prompt_color_merging) - set -g ___fish_git_prompt_color_merging_done (set_color normal) - else - set -g ___fish_git_prompt_color_merging $___fish_git_prompt_color - set -g ___fish_git_prompt_color_merging_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_branch - if test -n "$__fish_git_prompt_color_branch" - set -g ___fish_git_prompt_color_branch (set_color $__fish_git_prompt_color_branch) - set -g ___fish_git_prompt_color_branch_done (set_color normal) - else - set -g ___fish_git_prompt_color_branch $___fish_git_prompt_color - set -g ___fish_git_prompt_color_branch_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_cleanstate - if test -n "$__fish_git_prompt_color_cleanstate" - set -g ___fish_git_prompt_color_cleanstate (set_color $__fish_git_prompt_color_cleanstate) - set -g ___fish_git_prompt_color_cleanstate_done (set_color normal) - else - set -g ___fish_git_prompt_color_cleanstate $___fish_git_prompt_color - set -g ___fish_git_prompt_color_cleanstate_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_dirtystate - if test -n "$__fish_git_prompt_color_dirtystate" - set -g ___fish_git_prompt_color_dirtystate (set_color $__fish_git_prompt_color_dirtystate) - set -g ___fish_git_prompt_color_dirtystate_done (set_color normal) - else - set -g ___fish_git_prompt_color_dirtystate $___fish_git_prompt_color - set -g ___fish_git_prompt_color_dirtystate_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_stagedstate - if test -n "$__fish_git_prompt_color_stagedstate" - set -g ___fish_git_prompt_color_stagedstate (set_color $__fish_git_prompt_color_stagedstate) - set -g ___fish_git_prompt_color_stagedstate_done (set_color normal) - else - set -g ___fish_git_prompt_color_stagedstate $___fish_git_prompt_color - set -g ___fish_git_prompt_color_stagedstate_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_invalidstate - if test -n "$__fish_git_prompt_color_invalidstate" - set -g ___fish_git_prompt_color_invalidstate (set_color $__fish_git_prompt_color_invalidstate) - set -g ___fish_git_prompt_color_invalidstate_done (set_color normal) - else - set -g ___fish_git_prompt_color_invalidstate $___fish_git_prompt_color - set -g ___fish_git_prompt_color_invalidstate_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_stashstate - if test -n "$__fish_git_prompt_color_stashstate" - set -g ___fish_git_prompt_color_stashstate (set_color $__fish_git_prompt_color_stashstate) - set -g ___fish_git_prompt_color_stashstate_done (set_color normal) - else - set -g ___fish_git_prompt_color_stashstate $___fish_git_prompt_color - set -g ___fish_git_prompt_color_stashstate_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_untrackedfiles - if test -n "$__fish_git_prompt_color_untrackedfiles" - set -g ___fish_git_prompt_color_untrackedfiles (set_color $__fish_git_prompt_color_untrackedfiles) - set -g ___fish_git_prompt_color_untrackedfiles_done (set_color normal) - else - set -g ___fish_git_prompt_color_untrackedfiles $___fish_git_prompt_color - set -g ___fish_git_prompt_color_untrackedfiles_done $___fish_git_prompt_color_done - end - end - if not set -q ___fish_git_prompt_color_upstream - if test -n "$__fish_git_prompt_color_upstream" - set -g ___fish_git_prompt_color_upstream (set_color $__fish_git_prompt_color_upstream) - set -g ___fish_git_prompt_color_upstream_done (set_color normal) - else - set -g ___fish_git_prompt_color_upstream $___fish_git_prompt_color - set -g ___fish_git_prompt_color_upstream_done $___fish_git_prompt_color_done - end - end + + __fish_git_prompt_set_color __fish_git_prompt_color + __fish_git_prompt_set_color __fish_git_prompt_color_prefix + __fish_git_prompt_set_color __fish_git_prompt_color_suffix + __fish_git_prompt_set_color __fish_git_prompt_color_bare + __fish_git_prompt_set_color __fish_git_prompt_color_merging + __fish_git_prompt_set_color __fish_git_prompt_color_branch + __fish_git_prompt_set_color __fish_git_prompt_color_cleanstate + __fish_git_prompt_set_color __fish_git_prompt_color_dirtystate + __fish_git_prompt_set_color __fish_git_prompt_color_stagedstate + __fish_git_prompt_set_color __fish_git_prompt_color_invalidstate + __fish_git_prompt_set_color __fish_git_prompt_color_stashstate + __fish_git_prompt_set_color __fish_git_prompt_color_untrackedfiles + __fish_git_prompt_set_color __fish_git_prompt_color_upstream + end set -l varargs From a142c5e1ec99278b9ca235bbd71adf693be62373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Tue, 18 Jun 2013 22:20:28 +0200 Subject: [PATCH 07/25] Support for defining color with bold/brighter color set --- share/functions/__fish_git_prompt.fish | 15 +++++++++++++-- .../sample_prompts/informative_git.fish | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index bef8753c6..1b0b187aa 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -493,13 +493,24 @@ end function __fish_git_prompt_set_color set -l user_variable_name "$argv[1]" + set -l user_variable $$user_variable_name + set -l user_variable_bright + + if test (count $user_variable) -eq 2 + set user_variable_bright $user_variable[2] + set user_variable $user_variable[1] + end + set -l variable _$user_variable_name set -l variable_done "$variable"_done - set -l user_variable $$user_variable_name if not set -q $variable if test -n "$user_variable" - set -g $variable (set_color $user_variable) + if test -n "$user_variable_bright" + set -g $variable (set_color -o $user_variable) + else + set -g $variable (set_color $user_variable) + end set -g $variable_done (set_color normal) else set -g $variable '' diff --git a/share/tools/web_config/sample_prompts/informative_git.fish b/share/tools/web_config/sample_prompts/informative_git.fish index b7bf19f3a..f88150736 100644 --- a/share/tools/web_config/sample_prompts/informative_git.fish +++ b/share/tools/web_config/sample_prompts/informative_git.fish @@ -4,7 +4,7 @@ set -g __fish_git_prompt_show_status 1 set -g __fish_git_prompt_hide_untrackedfiles 1 -set -g __fish_git_prompt_color_branch magenta +set -g __fish_git_prompt_color_branch magenta bold set -g __fish_git_prompt_showupstream "informative" set -g __fish_git_prompt_char_upstream_ahead "↑" set -g __fish_git_prompt_char_upstream_behind "↓" @@ -20,7 +20,7 @@ set -g __fish_git_prompt_color_dirtystate blue set -g __fish_git_prompt_color_stagedstate yellow set -g __fish_git_prompt_color_invalidstate red set -g __fish_git_prompt_color_untrackedfiles $fish_color_normal -set -g __fish_git_prompt_color_cleanstate green +set -g __fish_git_prompt_color_cleanstate green bold function fish_prompt --description 'Write out the prompt' From 228fa382406e0a0bb4f230b77888a44fbc69d872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Tue, 18 Jun 2013 22:26:01 +0200 Subject: [PATCH 08/25] Renaming, cleanup --- share/functions/__fish_git_prompt.fish | 13 +++++-------- .../web_config/sample_prompts/informative_git.fish | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index 1b0b187aa..9b333aa15 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -233,14 +233,14 @@ function __fish_git_prompt --description "Prompt function for Git" set -l u #untracked set -l c (__fish_git_prompt_current_branch_bare) set -l p #upstream - set -l status_info + set -l informative_status __fish_git_prompt_validate_chars if test "true" = (git rev-parse --is-inside-work-tree ^/dev/null) - if test -n "$__fish_git_prompt_show_status" - set status_info "|"(__fish_git_prompt_status_info) + if test -n "$__fish_git_prompt_show_informative_status" + set informative_status "|"(__fish_git_prompt_informative_status) else if test -n "$__fish_git_prompt_showdirtystate" set -l config (git config --bool bash.showDirtyState) @@ -306,7 +306,7 @@ function __fish_git_prompt --description "Prompt function for Git" set format " (%s)" end - printf "%s$format%s" "$___fish_git_prompt_color_prefix" "$___fish_git_prompt_color_prefix_done$c$b$f$r$p$status_info$___fish_git_prompt_color_suffix" "$___git_ps_color_suffix_done" + printf "%s$format%s" "$___fish_git_prompt_color_prefix" "$___fish_git_prompt_color_prefix_done$c$b$f$r$p$informative_status$___fish_git_prompt_color_suffix" "$___git_ps_color_suffix_done" end ### helper functions @@ -334,7 +334,7 @@ function __fish_git_prompt_dirty --description "__fish_git_prompt helper, tells echo $dirty end -function __fish_git_prompt_status_info +function __fish_git_prompt_informative_status set -l changedFiles (git diff --name-status | cut -c 1-2) set -l stagedFiles (git diff --staged --name-status | cut -c 1-2) @@ -346,9 +346,6 @@ function __fish_git_prompt_status_info set -l info - __fish_git_prompt_validate_colors - __fish_git_prompt_validate_chars - if [ (math $dirtystate + $invalidstate + $stagedstate + $untrackedfiles) = 0 ] set info $___fish_git_prompt_color_cleanstate$___fish_git_prompt_char_cleanstate$___fish_git_prompt_color_cleanstate_done else diff --git a/share/tools/web_config/sample_prompts/informative_git.fish b/share/tools/web_config/sample_prompts/informative_git.fish index f88150736..466b40515 100644 --- a/share/tools/web_config/sample_prompts/informative_git.fish +++ b/share/tools/web_config/sample_prompts/informative_git.fish @@ -1,7 +1,7 @@ # name: Informative Git Prompt # author: Mariusz Smykula -set -g __fish_git_prompt_show_status 1 +set -g __fish_git_prompt_show_informative_status 1 set -g __fish_git_prompt_hide_untrackedfiles 1 set -g __fish_git_prompt_color_branch magenta bold From a3c87fb30bcf440977106cf7465e913ca09440e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Smyku=C5=82a?= Date: Tue, 18 Jun 2013 22:40:09 +0200 Subject: [PATCH 09/25] Less code is better, __fish_git_prompt_validate_chars refactoring --- share/functions/__fish_git_prompt.fish | 60 ++++++++++++-------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/share/functions/__fish_git_prompt.fish b/share/functions/__fish_git_prompt.fish index 9b333aa15..ea4df57a4 100644 --- a/share/functions/__fish_git_prompt.fish +++ b/share/functions/__fish_git_prompt.fish @@ -452,40 +452,34 @@ function __fish_git_prompt_git_dir --description "__fish_git_prompt helper, retu echo (git rev-parse --git-dir ^/dev/null) end +function __fish_git_prompt_set_char + set -l user_variable_name "$argv[1]" + set -l char $argv[2] + set -l user_variable $$user_variable_name + + set -l variable _$user_variable_name + set -l variable_done "$variable"_done + + if not set -q $variable + set -g $variable (set -q $user_variable_name; and echo $user_variable; or echo $char) + end + +end + function __fish_git_prompt_validate_chars --description "__fish_git_prompt helper, checks char variables" - if not set -q ___fish_git_prompt_char_cleanstate - set -g ___fish_git_prompt_char_cleanstate (set -q __fish_git_prompt_char_cleanstate; and echo $__fish_git_prompt_char_cleanstate; or echo '.') - end - if not set -q ___fish_git_prompt_char_dirtystate - set -g ___fish_git_prompt_char_dirtystate (set -q __fish_git_prompt_char_dirtystate; and echo $__fish_git_prompt_char_dirtystate; or echo '*') - end - if not set -q ___fish_git_prompt_char_stagedstate - set -g ___fish_git_prompt_char_stagedstate (set -q __fish_git_prompt_char_stagedstate; and echo $__fish_git_prompt_char_stagedstate; or echo '+') - end - if not set -q ___fish_git_prompt_char_invalidstate - set -g ___fish_git_prompt_char_invalidstate (set -q __fish_git_prompt_char_invalidstate; and echo $__fish_git_prompt_char_invalidstate; or echo '#') - end - if not set -q ___fish_git_prompt_char_stashstate - set -g ___fish_git_prompt_char_stashstate (set -q __fish_git_prompt_char_stashstate; and echo $__fish_git_prompt_char_stashstate; or echo '$') - end - if not set -q ___fish_git_prompt_char_untrackedfiles - set -g ___fish_git_prompt_char_untrackedfiles (set -q __fish_git_prompt_char_untrackedfiles; and echo $__fish_git_prompt_char_untrackedfiles; or echo '%') - end - if not set -q ___fish_git_prompt_char_upstream_equal - set -g ___fish_git_prompt_char_upstream_equal (set -q __fish_git_prompt_char_upstream_equal; and echo $__fish_git_prompt_char_upstream_equal; or echo '=') - end - if not set -q ___fish_git_prompt_char_upstream_behind - set -g ___fish_git_prompt_char_upstream_behind (set -q __fish_git_prompt_char_upstream_behind; and echo $__fish_git_prompt_char_upstream_behind; or echo '<') - end - if not set -q ___fish_git_prompt_char_upstream_ahead - set -g ___fish_git_prompt_char_upstream_ahead (set -q __fish_git_prompt_char_upstream_ahead; and echo $__fish_git_prompt_char_upstream_ahead; or echo '>') - end - if not set -q ___fish_git_prompt_char_upstream_diverged - set -g ___fish_git_prompt_char_upstream_diverged (set -q __fish_git_prompt_char_upstream_diverged; and echo $__fish_git_prompt_char_upstream_diverged; or echo '<>') - end - if not set -q ___fish_git_prompt_char_upstream_prefix - set -g ___fish_git_prompt_char_upstream_prefix (set -q __fish_git_prompt_char_upstream_prefix; and echo $__fish_git_prompt_char_upstream_prefix; or echo ' ') - end + + __fish_git_prompt_set_char __fish_git_prompt_char_cleanstate '.' + __fish_git_prompt_set_char __fish_git_prompt_char_dirtystate '*' + __fish_git_prompt_set_char __fish_git_prompt_char_stagedstate '+' + __fish_git_prompt_set_char __fish_git_prompt_char_invalidstate '#' + __fish_git_prompt_set_char __fish_git_prompt_char_stashstate '$' + __fish_git_prompt_set_char __fish_git_prompt_char_untrackedfiles '%' + __fish_git_prompt_set_char __fish_git_prompt_char_upstream_equal '=' + __fish_git_prompt_set_char __fish_git_prompt_char_upstream_behind '<' + __fish_git_prompt_set_char __fish_git_prompt_char_upstream_ahead '>' + __fish_git_prompt_set_char __fish_git_prompt_char_upstream_diverged '<>' + __fish_git_prompt_set_char __fish_git_prompt_char_upstream_prefix ' ' + end function __fish_git_prompt_set_color From 0fe44f0e2a10cb031a6f64723a35a32d60894ab2 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sat, 6 Jul 2013 20:57:41 +0530 Subject: [PATCH 10/25] Cleaned up commented lines and updated method names in create_manpage_completions script --- share/tools/create_manpage_completions.py | 136 +++++++--------------- 1 file changed, 43 insertions(+), 93 deletions(-) diff --git a/share/tools/create_manpage_completions.py b/share/tools/create_manpage_completions.py index 8d7aa59fd..24650ac6e 100755 --- a/share/tools/create_manpage_completions.py +++ b/share/tools/create_manpage_completions.py @@ -59,19 +59,19 @@ def flush_diagnostics(where): # This maps commands to lists of completions already_output_completions = {} -def compileAndSearch(regex, input): +def compile_and_search(regex, input): options_section_regex = re.compile(regex , re.DOTALL) options_section_matched = re.search( options_section_regex, input) return options_section_matched -def unquoteDoubleQuotes(data): +def unquote_double_quotes(data): if (len(data) < 2): return data if data[0] == '"' and data[len(data)-1] == '"': data = data[1:len(data)-1] return data -def unquoteSingleQuotes(data): +def unquote_single_quotes(data): if (len(data) < 2): return data if data[0] == '`' and data[len(data)-1] == '\'': @@ -188,11 +188,7 @@ def built_command(options, description): output_complete_command(escaped_cmd, fish_options, truncated_description, built_command_output) - - -def removeGroffFormatting(data): -# data = data.replace("\fI","") -# data = data.replace("\fP","") +def remove_groff_formatting(data): data = data.replace("\\fI","") data = data.replace("\\fP","") data = data.replace("\\f1","") @@ -217,26 +213,26 @@ def removeGroffFormatting(data): return data class ManParser: - def isMyType(self, manpage): + def is_my_type(self, manpage): return False - def parseManPage(self, manpage): + def parse_man_page(self, manpage): return False def name(self): return "no-name" class Type1ManParser(ManParser): - def isMyType(self, manpage): + def is_my_type(self, manpage): # print manpage - options_section_matched = compileAndSearch("\.SH \"OPTIONS\"(.*?)", manpage) + options_section_matched = compile_and_search("\.SH \"OPTIONS\"(.*?)", manpage) if options_section_matched == None: return False else: return True - def parseManPage(self, manpage): + def parse_man_page(self, manpage): options_section_regex = re.compile( "\.SH \"OPTIONS\"(.*?)(\.SH|\Z)", re.DOTALL) options_section_matched = re.search( options_section_regex, manpage) @@ -256,27 +252,22 @@ class Type1ManParser(ManParser): return False while (options_matched != None): - # print len(options_matched.groups()) - # print options_matched.group() data = options_matched.group(1) last_dotpp_index = data.rfind(".PP") if (last_dotpp_index != -1): data = data[last_dotpp_index+3:] - data = removeGroffFormatting(data) + data = remove_groff_formatting(data) data = data.split(".RS 4") - # print data if (len (data) > 1): #and len(data[1]) <= 300): optionName = data[0].strip() if ( optionName.find("-") == -1): add_diagnostic(optionName + " doesn't contain - ") -# return False else: - optionName = unquoteDoubleQuotes(optionName) - optionName = unquoteSingleQuotes(optionName) + optionName = unquote_double_quotes(optionName) + optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n"," ") -# print >> sys.stderr, "Option: ", optionName," Description: ", optionDescription , '\n' built_command(optionName, optionDescription) else: @@ -295,7 +286,7 @@ class Type1ManParser(ManParser): return False while options_matched != None: data = options_matched.group(2) - data = removeGroffFormatting(data) + data = remove_groff_formatting(data) data = data.strip() data = data.split("\n",1) if (len(data)>1 and len(data[1].strip())>0): # and len(data[1])<400): @@ -303,10 +294,9 @@ class Type1ManParser(ManParser): if ( optionName.find("-") == -1): add_diagnostic(optionName + "doesn't contains -") else: - optionName = unquoteDoubleQuotes(optionName) - optionName = unquoteSingleQuotes(optionName) + optionName = unquote_double_quotes(optionName) + optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n"," ") -# print "Option: ", optionName," Description: ", optionDescription , '\n' built_command(optionName, optionDescription) else: add_diagnostic('Unable to split option from description') @@ -330,27 +320,21 @@ class Type1ManParser(ManParser): while options_matched != None: data = options_matched.group(1) -# print "Data is : ", data - data = removeGroffFormatting(data) + data = remove_groff_formatting(data) data = data.strip() data = data.split("\n",1) if (len(data)>1 and len(data[1].strip())>0): # and len(data[1])<400): -# print "Data[0] is: ", data[0] - -# data = re.sub(trailing_num_regex, "", data) optionName = re.sub(trailing_num_regex, "", data[0].strip()) if ('-' not in optionName): add_diagnostic(optionName + " doesn't contain -") else: optionName = optionName.strip() - optionName = unquoteDoubleQuotes(optionName) - optionName = unquoteSingleQuotes(optionName) + optionName = unquote_double_quotes(optionName) + optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n"," ") -# print "Option: ", optionName," Description: ", optionDescription , '\n' built_command(optionName, optionDescription) else: -# print data add_diagnostic('Unable to split option from description') return False @@ -363,31 +347,21 @@ class Type1ManParser(ManParser): class Type2ManParser(ManParser): - def isMyType(self, manpage): - options_section_matched = compileAndSearch("\.SH OPTIONS(.*?)", manpage) + def is_my_type(self, manpage): + options_section_matched = compile_and_search("\.SH OPTIONS(.*?)", manpage) if options_section_matched == None: return False else: return True - def parseManPage(self, manpage): + def parse_man_page(self, manpage): options_section_regex = re.compile( "\.SH OPTIONS(.*?)(\.SH|\Z)", re.DOTALL) options_section_matched = re.search( options_section_regex, manpage) -# if (options_section_matched == None): -# print "Falling Back" -# options_section_regex = re.compile( "\.SH OPTIONS(.*?)$", re.DOTALL) -# options_section_matched = re.search( options_section_regex, manpage) -# print manpage options_section = options_section_matched.group(1) -# print options_section - # print options_section - # sys.exit(1) -# options_parts_regex = re.compile("\.TP(.*?)\.TP", re.DOTALL) options_parts_regex = re.compile("\.[I|T]P( \d+(\.\d)?i?)?(.*?)\.[I|T]P", re.DOTALL) -# options_parts_regex = re.compile("\.TP(.*?)[(\.TP)|(\.SH)]", re.DOTALL) options_matched = re.search(options_parts_regex, options_section) add_diagnostic('Command is ' + CMDNAME) @@ -396,56 +370,46 @@ class Type2ManParser(ManParser): return False while (options_matched != None): - # print len(options_matched.groups()) data = options_matched.group(3) - data = removeGroffFormatting(data) + data = remove_groff_formatting(data) data = data.strip() data = data.split("\n",1) -# print >> sys.stderr, data if (len(data)>1 and len(data[1].strip())>0): # and len(data[1])<400): optionName = data[0].strip() if '-' not in optionName: add_diagnostic(optionName + " doesn't contain -") else: - optionName = unquoteDoubleQuotes(optionName) - optionName = unquoteSingleQuotes(optionName) + optionName = unquote_double_quotes(optionName) + optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n"," ") -# print "Option: ", optionName," Description: ", optionDescription , '\n' built_command(optionName, optionDescription) else: - # print >> sys.stderr, data add_diagnostic('Unable to split option from description') -# return False - options_section = options_section[options_matched.end()-3:] options_matched = re.search(options_parts_regex, options_section) - - def name(self): return "Type2" class Type3ManParser(ManParser): - def isMyType(self, manpage): - options_section_matched = compileAndSearch("\.SH DESCRIPTION(.*?)", manpage) + def is_my_type(self, manpage): + options_section_matched = compile_and_search("\.SH DESCRIPTION(.*?)", manpage) if options_section_matched == None: return False else: return True - def parseManPage(self, manpage): + def parse_man_page(self, manpage): options_section_regex = re.compile( "\.SH DESCRIPTION(.*?)(\.SH|\Z)", re.DOTALL) options_section_matched = re.search( options_section_regex, manpage) options_section = options_section_matched.group(1) - # print options_section - # sys.exit(1) options_parts_regex = re.compile("\.TP(.*?)\.TP", re.DOTALL) options_matched = re.search(options_parts_regex, options_section) add_diagnostic('Command is ' + CMDNAME) @@ -455,10 +419,9 @@ class Type3ManParser(ManParser): return False while (options_matched != None): -# print len(options_matched.groups()) data = options_matched.group(1) - data = removeGroffFormatting(data) + data = remove_groff_formatting(data) data = data.strip() data = data.split("\n",1) @@ -467,10 +430,9 @@ class Type3ManParser(ManParser): if ( optionName.find("-") == -1): add_diagnostic(optionName + "doesn't contain -") else: - optionName = unquoteDoubleQuotes(optionName) - optionName = unquoteSingleQuotes(optionName) + optionName = unquote_double_quotes(optionName) + optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n"," ") -# print >> sys.stderr, "Option: ", optionName," Description: ", optionDescription , '\n' built_command(optionName, optionDescription) else: @@ -481,27 +443,24 @@ class Type3ManParser(ManParser): options_matched = re.search(options_parts_regex, options_section) - def name(self): return "Type3" class Type4ManParser(ManParser): - def isMyType(self, manpage): - options_section_matched = compileAndSearch("\.SH FUNCTION LETTERS(.*?)", manpage) + def is_my_type(self, manpage): + options_section_matched = compile_and_search("\.SH FUNCTION LETTERS(.*?)", manpage) if options_section_matched == None: return False else: return True - def parseManPage(self, manpage): + def parse_man_page(self, manpage): options_section_regex = re.compile( "\.SH FUNCTION LETTERS(.*?)(\.SH|\Z)", re.DOTALL) options_section_matched = re.search( options_section_regex, manpage) options_section = options_section_matched.group(1) - # print options_section - # sys.exit(1) options_parts_regex = re.compile("\.TP(.*?)\.TP", re.DOTALL) options_matched = re.search(options_parts_regex, options_section) add_diagnostic('Command is ' + CMDNAME) @@ -511,10 +470,9 @@ class Type4ManParser(ManParser): return False while (options_matched != None): - # print len(options_matched.groups()) data = options_matched.group(1) - data = removeGroffFormatting(data) + data = remove_groff_formatting(data) data = data.strip() data = data.split("\n",1) @@ -523,10 +481,9 @@ class Type4ManParser(ManParser): if ( optionName.find("-") == -1): add_diagnostic(optionName + " doesn't contain - ") else: - optionName = unquoteDoubleQuotes(optionName) - optionName = unquoteSingleQuotes(optionName) + optionName = unquote_double_quotes(optionName) + optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n"," ") -# print "Option: ", optionName," Description: ", optionDescription , '\n' built_command(optionName, optionDescription) else: @@ -542,8 +499,8 @@ class Type4ManParser(ManParser): return "Type4" class TypeDarwinManParser(ManParser): - def isMyType(self, manpage): - options_section_matched = compileAndSearch("\.S[hH] DESCRIPTION", manpage) + def is_my_type(self, manpage): + options_section_matched = compile_and_search("\.S[hH] DESCRIPTION", manpage) return options_section_matched != None def trim_groff(self, line): @@ -571,9 +528,6 @@ class TypeDarwinManParser(ManParser): result = result + 1 line = line[3:] return result - - - # Replace some groff escapes. There's a lot we don't bother to handle. def groff_replace_escapes(self, line): @@ -586,7 +540,7 @@ class TypeDarwinManParser(ManParser): def is_option(self, line): return line.startswith('.It Fl') - def parseManPage(self, manpage): + def parse_man_page(self, manpage): got_something = False lines = manpage.splitlines() # Discard lines until we get to ".sh Description" @@ -626,9 +580,6 @@ class TypeDarwinManParser(ManParser): desc_lines.append(line) desc = ' '.join(desc_lines) - # print "name: ", name - # print "desc: ", desc - if name == '-': # Skip double -- arguments continue @@ -647,7 +598,7 @@ class TypeDarwinManParser(ManParser): class TypeDeroffManParser(ManParser): - def isMyType(self, manpage): + def is_my_type(self, manpage): return True # We're optimists def is_option(self, line): @@ -656,7 +607,7 @@ class TypeDeroffManParser(ManParser): def could_be_description(self, line): return len(line) > 0 and not line.startswith('-') - def parseManPage(self, manpage): + def parse_man_page(self, manpage): d = Deroffer() d.deroff(manpage) output = d.get_output() @@ -697,7 +648,6 @@ class TypeDeroffManParser(ManParser): return got_something - def name(self): return "Deroffing man parser" @@ -800,7 +750,7 @@ def parse_manpage_at_path(manpage_path, output_directory): parsers = [TypeDeroffManParser()] else: parsers = [Type1ManParser(), Type2ManParser(), Type4ManParser(), Type3ManParser(), TypeDarwinManParser(), TypeDeroffManParser()] - parsersToTry = [p for p in parsers if p.isMyType(manpage)] + parsersToTry = [p for p in parsers if p.is_my_type(manpage)] success = False if not parsersToTry: @@ -810,7 +760,7 @@ def parse_manpage_at_path(manpage_path, output_directory): parser_name = parser.name() add_diagnostic('Trying parser ' + parser_name) diagnostic_indent += 1 - success = parser.parseManPage(manpage) + success = parser.parse_man_page(manpage) diagnostic_indent -= 1 # Make sure empty files aren't reported as success if not built_command_output: From 379cf3d24915d4b064ab60d62c20f67ebdd4126e Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sat, 6 Jul 2013 21:09:20 +0530 Subject: [PATCH 11/25] Converted tabs to spaces in webconfig script --- share/tools/web_config/webconfig.py | 66 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py index 8b5b24f92..4f07fd9d7 100755 --- a/share/tools/web_config/webconfig.py +++ b/share/tools/web_config/webconfig.py @@ -75,7 +75,6 @@ def better_color(c1, c2): if c1 in named_colors: return c2 return c1 - def parse_color(color_str): """ A basic function to parse a color string, for example, 'red' '--bold' """ comps = color_str.split(' ') @@ -98,7 +97,6 @@ def parse_color(color_str): return [color, background_color, bold, underline] - def parse_bool(val): val = val.lower() if val.startswith('f') or val.startswith('0'): return False @@ -229,11 +227,11 @@ def ansi_to_html(val): # Clean up empty spans, the nasty way idx = len(result) - 1 while idx >= 1: - if result[idx] == '' and result[idx-1].startswith('' and result[idx-1].startswith(' Date: Fri, 28 Jun 2013 13:07:56 +0200 Subject: [PATCH 12/25] Fix broken darcs completion --- share/completions/darcs.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/completions/darcs.fish b/share/completions/darcs.fish index 65fc9179a..9a826da0f 100644 --- a/share/completions/darcs.fish +++ b/share/completions/darcs.fish @@ -41,7 +41,7 @@ complete -c darcs -n '__fish_use_subcommand' -x -a obliterate --description 'Del complete -c darcs -n '__fish_use_subcommand' -x -a rollback --description 'Record a new patch reversing some recorded changes' complete -c darcs -n '__fish_use_subcommand' -x -a push --description 'Copy and apply patches from this repository to another one' complete -c darcs -n '__fish_use_subcommand' -x -a send --description 'Send by email a bundle of one or more patches' -complete -c darcs -n '__fish_use_subcommand' -x -a apply --description 'Apply a patch bundle created by `darcs send'' +complete -c darcs -n '__fish_use_subcommand' -x -a apply --description 'Apply a patch bundle created by `darcs send\'' complete -c darcs -n '__fish_use_subcommand' -x -a get --description 'Create a local copy of a repository' complete -c darcs -n '__fish_use_subcommand' -x -a put --description 'Makes a copy of the repository' complete -c darcs -n '__fish_use_subcommand' -x -a initialize --description 'Make the current directory a repository' From d3bb2a718aa69bf58331a833a7dad07cb2e1dbcc Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Tue, 16 Jul 2013 13:25:42 -0700 Subject: [PATCH 13/25] Make printf support \e as the escape character https://github.com/fish-shell/fish-shell/issues/910 --- builtin_printf.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index e164f8193..f6cef3d6c 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -26,6 +26,7 @@ \a = alert (bell) \b = backspace \c = produce no further output + \e = escape \f = form feed \n = new line \r = carriage return @@ -319,6 +320,9 @@ void builtin_printf_state_t::print_esc_char(wchar_t c) case L'c': /* Cancel the rest of the output. */ this->early_exit = true; break; + case L'e': /* Escape */ + this->append_output(L'\x1B'); + break; case L'f': /* Form feed. */ this->append_output(L'\f'); break; @@ -369,8 +373,10 @@ long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0) esc_value = esc_value * 8 + octal_to_bin(*p); this->append_format_output(L"%c", esc_value); } - else if (*p && wcschr(L"\"\\abcfnrtv", *p)) + else if (*p && wcschr(L"\"\\abcefnrtv", *p)) + { print_esc_char(*p++); + } else if (*p == L'u' || *p == L'U') { wchar_t esc_char = *p; From 28fdfec7cbb9bffb0492f12fed0d27e1524b12a6 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Tue, 16 Jul 2013 13:37:55 -0700 Subject: [PATCH 14/25] Add -Wall to Xcode build --- fish.xcodeproj/project.pbxproj | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fish.xcodeproj/project.pbxproj b/fish.xcodeproj/project.pbxproj index b48ea5771..f4e7160a3 100644 --- a/fish.xcodeproj/project.pbxproj +++ b/fish.xcodeproj/project.pbxproj @@ -1189,7 +1189,7 @@ "PREFIX=L\\\"/usr/local\\\"", "DATADIR=L\\\"/usr/local/share\\\"", "SYSCONFDIR=L\\\"/usr/local/etc\\\"", - "BINDIR=L\\\"/usr/local/bin\\\"", + "BINDIR=L\\\"/usr/local/bin\\\"", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -1197,6 +1197,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.7; SDKROOT = macosx; USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/**"; + WARNING_CFLAGS = "-Wall"; }; name = "Release_C++11"; }; @@ -1339,7 +1340,7 @@ "PREFIX=L\\\"/usr/local\\\"", "DATADIR=L\\\"/usr/local/share\\\"", "SYSCONFDIR=L\\\"/usr/local/etc\\\"", - "BINDIR=L\\\"/usr/local/bin\\\"", + "BINDIR=L\\\"/usr/local/bin\\\"", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -1349,6 +1350,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/**"; + WARNING_CFLAGS = "-Wall"; }; name = Debug; }; @@ -1365,7 +1367,7 @@ "PREFIX=L\\\"/usr/local\\\"", "DATADIR=L\\\"/usr/local/share\\\"", "SYSCONFDIR=L\\\"/usr/local/etc\\\"", - "BINDIR=L\\\"/usr/local/bin\\\"", + "BINDIR=L\\\"/usr/local/bin\\\"", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -1373,6 +1375,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.6; SDKROOT = macosx; USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/osx/**"; + WARNING_CFLAGS = "-Wall"; }; name = Release; }; From c522c0833a199dfeb333dd2515b75660ddeee330 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Tue, 16 Jul 2013 13:38:15 -0700 Subject: [PATCH 15/25] Fix warnings about array subscript in builtin_printf.cpp --- builtin_printf.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index f6cef3d6c..0e35b129a 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -581,6 +581,16 @@ void builtin_printf_state_t::print_direc(const wchar_t *start, size_t length, wc } } +/* For each character in str, set the corresponding boolean in the array to the given flag */ +static inline void modify_allowed_format_specifiers(bool ok[UCHAR_MAX + 1], const char *str, bool flag) +{ + for (const char *c = str; *c != '\0'; c++) + { + unsigned char idx = static_cast(*c); + ok[idx] = flag; + } +} + /* Print the text in FORMAT, using ARGV (with ARGC elements) for arguments to any `%' directives. Return the number of elements of ARGV used. */ @@ -622,10 +632,8 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch } break; } - - ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] = - ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] = - ok['s'] = ok['u'] = ok['x'] = ok['X'] = true; + + modify_allowed_format_specifiers(ok, "aAcdeEfFgGiosuxX", true); for (;; f++, direc_length++) { @@ -633,18 +641,17 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch { case L'I': case L'\'': - ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = - ok['o'] = ok['s'] = ok['x'] = ok['X'] = false; + modify_allowed_format_specifiers(ok, "aAceEosxX", false); break; case '-': case '+': case ' ': break; case L'#': - ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = false; + modify_allowed_format_specifiers(ok, "cdisu", false); break; case '0': - ok['c'] = ok['s'] = false; + modify_allowed_format_specifiers(ok, "cs", false); break; default: goto no_more_flag_characters; @@ -685,7 +692,7 @@ no_more_flag_characters: { ++f; ++direc_length; - ok['c'] = false; + modify_allowed_format_specifiers(ok, "c", false); if (*f == L'*') { ++f; From c64a86efae2105537650d2d627fe40e7fb6cb61f Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Tue, 16 Jul 2013 13:40:11 -0700 Subject: [PATCH 16/25] Fix some warnings exposed by -Wall --- env.cpp | 1 - fish.cpp | 30 ------------------------------ 2 files changed, 31 deletions(-) diff --git a/env.cpp b/env.cpp index 398425c22..ddb5d2c4e 100644 --- a/env.cpp +++ b/env.cpp @@ -137,7 +137,6 @@ struct env_node_t class variable_entry_t { - bool exportv; /**< Whether the variable should be exported */ wcstring value; /**< Value of the variable */ }; diff --git a/fish.cpp b/fish.cpp index abefa8985..8001f3764 100644 --- a/fish.cpp +++ b/fish.cpp @@ -382,36 +382,6 @@ static int fish_parse_opt(int argc, char **argv, std::vector *out_c return my_optind; } -/** - Calls a bunch of init functions, parses the init files and then - parses commands from stdin or files, depending on arguments -*/ - -static wcstring full_escape(const wchar_t *in) -{ - wcstring out; - for (; *in; in++) - { - if (*in < 32) - { - append_format(out, L"\\x%.2x", *in); - } - else if (*in < 128) - { - out.push_back(*in); - } - else if (*in < 65536) - { - append_format(out, L"\\u%.4x", *in); - } - else - { - append_format(out, L"\\U%.8x", *in); - } - } - return out; -} - extern int g_fork_count; int main(int argc, char **argv) { From d6c9d3ce948c6bff13431c195f65860b5a1f0230 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Fri, 12 Jul 2013 09:40:29 +0200 Subject: [PATCH 17/25] Use \x1B instead of \e. --- builtin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin.cpp b/builtin.cpp index 9796d356f..52c06ac85 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -1658,7 +1658,7 @@ static int builtin_echo(parser_t &parser, wchar_t **argv) wc = L'\b'; break; case L'e': - wc = L'\e'; + wc = L'\x1B'; break; case L'f': wc = L'\f'; From 1511de68ed847c82989561c2619f5f817097ad38 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 17 Jul 2013 01:35:30 -0700 Subject: [PATCH 18/25] Make parse_util_locate_cmdsubst return the innermost command substitution instead of the outermost. Fixes https://github.com/fish-shell/fish-shell/issues/913 --- expand.cpp | 10 +---- fish_tests.cpp | 26 ++++++++++++ highlight.cpp | 4 +- parse_util.cpp | 105 ++++++++++++++++++------------------------------- parse_util.h | 4 +- parser.cpp | 2 +- 6 files changed, 72 insertions(+), 79 deletions(-) diff --git a/expand.cpp b/expand.cpp index 6dfa9e448..e25109fc0 100644 --- a/expand.cpp +++ b/expand.cpp @@ -1336,10 +1336,7 @@ static int expand_cmdsubst(parser_t &parser, const wcstring &input, std::vector< const wchar_t * const in = input.c_str(); int parse_ret; - switch (parse_ret = parse_util_locate_cmdsubst(in, - ¶n_begin, - ¶n_end, - 0)) + switch (parse_ret = parse_util_locate_cmdsubst(in, ¶n_begin, ¶n_end, false)) { case -1: parser.error(SYNTAX_ERROR, @@ -1628,10 +1625,7 @@ int expand_string(const wcstring &input, std::vector &output, expa { wchar_t *begin, *end; - if (parse_util_locate_cmdsubst(input.c_str(), - &begin, - &end, - 1) != 0) + if (parse_util_locate_cmdsubst(input.c_str(), &begin, &end, true) != 0) { parser.error(CMDSUBST_ERROR, -1, L"Command substitutions not allowed"); return EXPAND_ERROR; diff --git a/fish_tests.cpp b/fish_tests.cpp index 2572e8d6a..fad9b7ecb 100644 --- a/fish_tests.cpp +++ b/fish_tests.cpp @@ -60,6 +60,7 @@ #include "postfork.h" #include "signal.h" #include "highlight.h" +#include "parse_util.h" /** The number of tests to run @@ -527,6 +528,30 @@ static void test_parser() } } +static void test_utils() +{ + say(L"Testing utils"); + const wchar_t *a = L"echo (echo (echo hi"; + + const wchar_t *begin = NULL, *end = NULL; + parse_util_cmdsubst_extent(a, 0, &begin, &end); + if (begin != a || end - begin != wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + parse_util_cmdsubst_extent(a, 1, &begin, &end); + if (begin != a || end - begin != wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + parse_util_cmdsubst_extent(a, 2, &begin, &end); + if (begin != a || end - begin != wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + parse_util_cmdsubst_extent(a, 3, &begin, &end); + if (begin != a || end - begin != wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + + parse_util_cmdsubst_extent(a, 8, &begin, &end); + if (begin != a + wcslen(L"echo (")) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + + parse_util_cmdsubst_extent(a, 17, &begin, &end); + if (begin != a + wcslen(L"echo (echo (")) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + + +} + class lru_node_test_t : public lru_node_t { public: @@ -1747,6 +1772,7 @@ int main(int argc, char **argv) test_tok(); test_fork(); test_parser(); + test_utils(); test_lru(); test_expand(); test_fuzzy_match(); diff --git a/highlight.cpp b/highlight.cpp index 8ea0989e6..265fd40af 100644 --- a/highlight.cpp +++ b/highlight.cpp @@ -1319,7 +1319,7 @@ void highlight_shell(const wcstring &buff, std::vector &color, size_t pos, std::fill(color.begin(), color.end(), -1); - /* Do something sucky and get the current working directory on this background thread. This should really be passed in. Note that we also need this as a vector (of one directory). */ + /* Do something sucky and get the current working directory on this background thread. This should really be passed in. */ const wcstring working_directory = env_get_pwd_slash(); /* Tokenize the string */ @@ -1335,7 +1335,7 @@ void highlight_shell(const wcstring &buff, std::vector &color, size_t pos, { wchar_t *begin, *end; - if (parse_util_locate_cmdsubst(subpos, &begin, &end, 1) <= 0) + if (parse_util_locate_cmdsubst(subpos, &begin, &end, true) <= 0) { break; } diff --git a/parse_util.cpp b/parse_util.cpp index a7614f0c2..e6d04a3f9 100644 --- a/parse_util.cpp +++ b/parse_util.cpp @@ -153,10 +153,7 @@ size_t parse_util_get_offset(const wcstring &str, int line, long line_offset) } -int parse_util_locate_cmdsubst(const wchar_t *in, - wchar_t **begin, - wchar_t **end, - int allow_incomplete) +int parse_util_locate_cmdsubst(const wchar_t *in, wchar_t **begin, wchar_t **end, bool allow_incomplete) { wchar_t *pos; wchar_t prev=0; @@ -243,73 +240,57 @@ int parse_util_locate_cmdsubst(const wchar_t *in, return 1; } - -void parse_util_cmdsubst_extent(const wchar_t *buff, - size_t cursor_pos, - const wchar_t **a, - const wchar_t **b) +void parse_util_cmdsubst_extent(const wchar_t *buff, size_t cursor_pos, const wchar_t **a, const wchar_t **b) { - wchar_t *begin, *end; - wchar_t *pos; - const wchar_t *cursor = buff + cursor_pos; + const wchar_t * const cursor = buff + cursor_pos; CHECK(buff,); - - if (a) + + const size_t bufflen = wcslen(buff); + assert(cursor_pos <= bufflen); + + /* ap and bp are the beginning and end of the tightest command substitition found so far */ + const wchar_t *ap = buff, *bp = buff + bufflen; + const wchar_t *pos = buff; + for (;;) { - *a = (wchar_t *)buff; - } - - if (b) - { - *b = (wchar_t *)buff+wcslen(buff); - } - - pos = (wchar_t *)buff; - - while (1) - { - if (parse_util_locate_cmdsubst(pos, - &begin, - &end, - 1) <= 0) + wchar_t *begin = NULL, *end = NULL; + if (parse_util_locate_cmdsubst(pos, &begin, &end, true) <= 0) { - /* - No subshell found - */ + /* No subshell found, all done */ break; } - - if (!end) + + /* Intrepret NULL to mean the end */ + if (end == NULL) { - end = (wchar_t *)buff + wcslen(buff); + end = const_cast(buff) + bufflen; } - - if ((begin < cursor) && (end >= cursor)) + + if (begin < cursor && end >= cursor) { + /* This command substitution surrounds the cursor, so it's a tighter fit */ begin++; - - if (a) - { - *a = begin; - } - - if (b) - { - *b = end; - } - - break; + ap = begin; + bp = end; + pos = begin + 1; } - - if (!*end) + else if (begin >= cursor) { + /* This command substitution starts at or after the cursor. Since it was the first command substitution in the string, we're done. */ break; } - - pos = end+1; + else + { + /* This command substitution ends before the cursor. Skip it. */ + assert(end < cursor); + pos = end + 1; + assert(pos <= buff + bufflen); + } } - + + if (a != NULL) *a = ap; + if (b != NULL) *b = bp; } /** @@ -432,7 +413,6 @@ void parse_util_token_extent(const wchar_t *buff, { const wchar_t *begin, *end; long pos; - wchar_t *buffcpy; const wchar_t *a = NULL, *b = NULL, *pa = NULL, *pb = NULL; @@ -459,14 +439,9 @@ void parse_util_token_extent(const wchar_t *buff, assert(end >= begin); assert(end <= (buff+wcslen(buff))); - buffcpy = wcsndup(begin, end-begin); + const wcstring buffcpy = wcstring(begin, end-begin); - if (!buffcpy) - { - DIE_MEM(); - } - - tokenizer_t tok(buffcpy, TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS); + tokenizer_t tok(buffcpy.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS); for (; tok_has_next(&tok); tok_next(&tok)) { size_t tok_begin = tok_get_pos(&tok); @@ -512,8 +487,6 @@ void parse_util_token_extent(const wchar_t *buff, } } - free(buffcpy); - if (tok_begin) { *tok_begin = a; @@ -679,7 +652,7 @@ static wchar_t get_quote(const wchar_t *cmd, size_t len) { const wchar_t *end = quote_end(&cmd[i]); //fwprintf( stderr, L"Jump %d\n", end-cmd ); - if ((end == 0) || (!*end) || (end-cmd > len)) + if ((end == 0) || (!*end) || (end > cmd + len)) { res = cmd[i]; break; diff --git a/parse_util.h b/parse_util.h index b8e370f76..24147e180 100644 --- a/parse_util.h +++ b/parse_util.h @@ -18,14 +18,14 @@ \param in the string to search for subshells \param begin the starting paranthesis of the subshell \param end the ending paranthesis of the subshell - \param flags set this variable to ACCEPT_INCOMPLETE if in tab_completion mode + \param accept_incomplete whether to permit missing closing parenthesis \return -1 on syntax error, 0 if no subshells exist and 1 on sucess */ int parse_util_locate_cmdsubst(const wchar_t *in, wchar_t **begin, wchar_t **end, - int flags); + bool accept_incomplete); /** Find the beginning and end of the command substitution under the diff --git a/parser.cpp b/parser.cpp index 1bc262ea6..a8390af84 100644 --- a/parser.cpp +++ b/parser.cpp @@ -2716,7 +2716,7 @@ int parser_t::parser_test_argument(const wchar_t *arg, wcstring *out, const wcha switch (parse_util_locate_cmdsubst(arg_cpy, ¶n_begin, ¶n_end, - 0)) + false)) { case -1: err=1; From 91a04c7638bbfbe8abb59d17b2c6b8aeb7b04a05 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 17 Jul 2013 15:24:23 +0200 Subject: [PATCH 19/25] printf '\0' now works. Fixes #908. --- builtin_printf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index e164f8193..a382da067 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -358,7 +358,7 @@ long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0) esc_value = esc_value * 16 + hex_to_bin(*p); if (esc_length == 0) this->fatal_error(_(L"missing hexadecimal number in escape")); - this->append_format_output(L"%lc", esc_value); + this->append_output(esc_value); } else if (is_octal_digit(*p)) { @@ -367,7 +367,7 @@ long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0) extension to POSIX that is compatible with Bash 2.05b. */ for (esc_length = 0, p += octal_0 && *p == L'0'; esc_length < 3 && is_octal_digit(*p); ++esc_length, ++p) esc_value = esc_value * 8 + octal_to_bin(*p); - this->append_format_output(L"%c", esc_value); + this->append_output(esc_value); } else if (*p && wcschr(L"\"\\abcfnrtv", *p)) print_esc_char(*p++); From 7353c6f94db0adfc37c0cca9882db41e252fd82d Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Thu, 18 Jul 2013 21:26:32 +0530 Subject: [PATCH 20/25] Fixed ftp completions Merged pull request at https://github.com/fish-shell/fish-shell/pull/919 Squashed commit of the following: commit c0662a9d4da12ba49ffe1dddc918533f8a52b91f Author: Siteshwar Vashisht Date: Thu Jul 18 21:23:42 2013 +0530 Added missing quote in ftp completions commit 9ef408d0390f13be3adc02be62daae3e0f114843 Author: Konrad Borowski Date: Thu Jul 18 15:33:57 2013 +0200 Make punctuation consistent properly. Fixes #918. commit ea26da0f8284fa39dc143e3d2ad088403fa6b2ed Author: Konrad Borowski Date: Thu Jul 18 15:29:02 2013 +0200 Revert "make punctuation consistent" This reverts commit 993c02857948b45e5d17cc2696f347c73b3a450d. --- share/functions/__fish_complete_ftp.fish | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/share/functions/__fish_complete_ftp.fish b/share/functions/__fish_complete_ftp.fish index bc69acaf3..92ff0b088 100644 --- a/share/functions/__fish_complete_ftp.fish +++ b/share/functions/__fish_complete_ftp.fish @@ -1,22 +1,14 @@ function __fish_complete_ftp -d 'Complete ftp, pftp' --argument-names ftp complete -c $ftp -xa "(__fish_print_hostnames)" -d 'Hostname' -tname' - complete -c $ftp -s 4 -d 'Use only IPv4 to contact any host' - host' - complete -c $ftp -s 6 -d 'Use IPv6 only' - only' - complete -c $ftp -s p -d 'Use passive mode for data transfers' -sfers' - complete -c $ftp -s A -d 'Use active mode for data transfers' -sfers' - complete -c $ftp -s i -d 'Turn off interactive prompting during multiple file transfers' + complete -c $ftp -s 4 -d 'Use only IPv4 to contact any host' + complete -c $ftp -s 6 -d 'Use IPv6 only' + complete -c $ftp -s p -d 'Use passive mode for data transfers' + complete -c $ftp -s A -d 'Use active mode for data transfers' + complete -c $ftp -s i -d 'Turn off interactive prompting during multiple file transfers.' complete -c $ftp -s n -d 'Restrain ftp from attempting "auto-login" upon initial connection' complete -c $ftp -s e -d 'Disable command editing and history support' complete -c $ftp -s g -d 'Disable file name globbing' -Disable file name globbing' -m -d 'Do not explicitly bind data and control channels to same interface' -channels to same interface' -v -d 'Verbose. Show all server responses and data transfer stats' -es and data transfer stats' -d -d 'Enable debugging' + complete -c $ftp -s m -d 'Do not explicitly bind data and control channels to same interface' + complete -c $ftp -s v -d 'Verbose. Show all server responses and data transfer stats' + complete -c $ftp -s d -d 'Enable debugging' end From 51ae9b3ed435f740672df5ed092e4ce95e3f4dbc Mon Sep 17 00:00:00 2001 From: Johann Weging Date: Sun, 2 Jun 2013 15:26:36 +0200 Subject: [PATCH 21/25] Add completion for canto. --- share/completions/canto.fish | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 share/completions/canto.fish diff --git a/share/completions/canto.fish b/share/completions/canto.fish new file mode 100644 index 000000000..ad75b4cf9 --- /dev/null +++ b/share/completions/canto.fish @@ -0,0 +1,35 @@ + +function __fish_canto_using_command + set cmd (commandline -opc) + if [ (count $cmd) -gt 1 ] + if [ $argv[1] = $cmd[2] ] + return 0 + end + if [ count $argv -gt 2 ] + if [ $argv[2] = $cmd[2] ] + return 0 + end + end + end + return 1 +end + + +complete -f -c canto -s h -l help -d 'Show Help' +complete -f -c canto -s v -l version -d 'Show version' +complete -f -c canto -s u -l update -d 'Update before running' +complete -f -c canto -s l -l list -d 'List feeds' +complete -f -c canto -s a -l checkall -d 'Show number of new items' + +complete -f -c canto -s n -l checknew -d 'Show number of new items for feed' +complete -f -c canto -n '__fish_canto_using_command -l --checknew' -d 'Feed' -a '(command canto -l)' + +complete -c canto -s o -l opml -d 'Print conf as OPML' +complete -c cnato -s i -l import -d 'Import from OPML' +complete -f -c canto -s r -l url -d 'Add feed' + +complete -c canto -s D -l dir -d 'Set configuration directory' +complete -c canto -s C -l conf -d 'Set configuration file' +complete -c canto -s L -l log -d 'Set client log file' +complete -c canto -s F -l fdir -d 'Set feed directory' +complete -c canto -s S -l sdir 'Set script directory' From 97bea94550819efcdffb1213b5d425d5f1af66d9 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Fri, 19 Jul 2013 09:28:05 +0200 Subject: [PATCH 22/25] Fix canto completion -d option was forgotten, causing error for last complete command --- share/completions/canto.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/completions/canto.fish b/share/completions/canto.fish index ad75b4cf9..7c487fb75 100644 --- a/share/completions/canto.fish +++ b/share/completions/canto.fish @@ -32,4 +32,4 @@ complete -c canto -s D -l dir -d 'Set configuration directory' complete -c canto -s C -l conf -d 'Set configuration file' complete -c canto -s L -l log -d 'Set client log file' complete -c canto -s F -l fdir -d 'Set feed directory' -complete -c canto -s S -l sdir 'Set script directory' +complete -c canto -s S -l sdir -d 'Set script directory' From 58ad04b61cf567c7a8756869f19d6d5682122b12 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Fri, 19 Jul 2013 09:56:47 +0200 Subject: [PATCH 23/25] Avoid standard command not found message when command-not-found is found Squashed commit of the following: commit c208bc30b7747b3743212483b3dd7e3f90819f49 Merge: 97bea94 2633372 Author: Konrad Borowski Date: Fri Jul 19 09:56:12 2013 +0200 Merge branch 'command-not-found' of git://github.com/GlitchMr/fish-shell into command-not-found commit 26333721b9048333d1e7932505c221a31fd0e624 Author: Konrad Borowski Date: Fri Jul 19 09:55:13 2013 +0200 Fix command_not_found when not found commit db34460bb51a4b1c1c456c2e535ae8d913d1071e Author: Konrad Borowski Date: Wed Jul 17 13:41:57 2013 +0200 Avoid showing standard command not found message when possible In bash, command-not-found handler causes the standard messages to not appear. Because of events model in fish, it isn't really an option, so I moved the standard command not found message to fish function. This way, the messages aren't repeated, and the standard command not found message appears only when handler couldn't be found. --- parser.cpp | 16 ++++++++++------ share/functions/__fish_config_interactive.fish | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/parser.cpp b/parser.cpp index a8390af84..d6aa18868 100644 --- a/parser.cpp +++ b/parser.cpp @@ -2027,6 +2027,7 @@ int parser_t::parse_job(process_t *p, for this, used by other shells like bash and zsh). */ + if (wcschr(cmd, L'=')) { wchar_t *cpy = wcsdup(cmd); @@ -2076,9 +2077,15 @@ int parser_t::parse_job(process_t *p, } else { - debug(0, - _(L"Unknown command '%ls'"), - cmd?cmd:L"UNKNOWN"); + /* + Handle unrecognized commands with standard + command not found handler that can make better + error messages + */ + + wcstring_list_t event_args; + event_args.push_back(args.at(0).completion); + event_fire_generic(L"fish_command_not_found", &event_args); } tmp = current_tokenizer_pos; @@ -2090,9 +2097,6 @@ int parser_t::parse_job(process_t *p, job_set_flag(j, JOB_SKIP, 1); - wcstring_list_t event_args; - event_args.push_back(args.at(0).completion); - event_fire_generic(L"fish_command_not_found", &event_args); proc_set_last_status(err==ENOENT?STATUS_UNKNOWN_COMMAND:STATUS_NOT_EXECUTABLE); } } diff --git a/share/functions/__fish_config_interactive.fish b/share/functions/__fish_config_interactive.fish index 814fff198..d7961861f 100644 --- a/share/functions/__fish_config_interactive.fish +++ b/share/functions/__fish_config_interactive.fish @@ -218,21 +218,23 @@ function __fish_config_interactive -d "Initializations that should be performed function fish_command_not_found_setup --on-event fish_command_not_found # Remove fish_command_not_found_setup so we only execute this once functions --erase fish_command_not_found_setup - + # First check in /usr/lib, this is where modern Ubuntus place this command if test -f /usr/lib/command-not-found function fish_command_not_found_handler --on-event fish_command_not_found /usr/lib/command-not-found $argv end - fish_command_not_found_handler $argv + # Ubuntu Feisty places this command in the regular path instead + else if type -p command-not-found > /dev/null 2> /dev/null + function fish_command_not_found_handler --on-event fish_command_not_found + command-not-found $argv + end + # Use standard fish command not found handler otherwise else - # Ubuntu Feisty places this command in the regular path instead - if type -p command-not-found > /dev/null 2> /dev/null - function fish_command_not_found_handler --on-event fish_command_not_found - command-not-found $argv - end - fish_command_not_found_handler $argv + function fish_command_not_found_handler --on-event fish_command_not_found + echo fish: Unknown command "'$argv'" >&2 end end + fish_command_not_found_handler $argv end end From 92099c7af23d0cebf52f89de4f9d829825e53ac8 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 17 Jul 2013 00:38:04 -0700 Subject: [PATCH 24/25] Initial abbreviation work. Tests currently fail. --- builtin.cpp | 3 +- expand.cpp | 39 +++++++++++ expand.h | 4 ++ fish_tests.cpp | 62 ++++++++++++++++++ reader.cpp | 175 +++++++++++++++++++++++++++++++++++++++++++++++-- reader.h | 7 ++ 6 files changed, 285 insertions(+), 5 deletions(-) diff --git a/builtin.cpp b/builtin.cpp index 52c06ac85..d230080a4 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -2370,8 +2370,9 @@ static int builtin_read(parser_t &parser, wchar_t **argv) reader_set_highlight_function(&highlight_shell); reader_set_test_function(&reader_shell_test); } - /* No autosuggestions in builtin_read */ + /* No autosuggestions or abbreviations in builtin_read */ reader_set_allow_autosuggesting(false); + reader_set_expand_abbreviations(false); reader_set_exit_on_interrupt(true); reader_set_buffer(commandline, wcslen(commandline)); diff --git a/expand.cpp b/expand.cpp index e25109fc0..dc83c385d 100644 --- a/expand.cpp +++ b/expand.cpp @@ -1933,3 +1933,42 @@ bool fish_openSUSE_dbus_hack_hack_hack_hack(std::vector *args) } return result; } + +bool expand_abbreviation(const wcstring &src, wcstring *output) +{ + if (src.empty()) + return false; + + /* Get the abbreviations. Return false if we have none */ + env_var_t var = env_get_string(USER_ABBREVIATIONS_VARIABLE_NAME); + if (var.missing_or_empty()) + return false; + + bool result = false; + wcstring line; + wcstokenizer tokenizer(var, ARRAY_SEP_STR); + while (tokenizer.next(line)) + { + /* Line is expected to be of the form 'foo=bar'. Parse out the first =. Be forgiving about spaces, but silently skip on failure (no equals, or equals at the end or beginning). Try to avoid copying any strings until we are sure this is a match. */ + size_t equals = line.find(L'='); + if (equals == wcstring::npos || equals == 0 || equals + 1 == line.size()) + continue; + + /* Find the character just past the end of the command. Walk backwards, skipping spaces. */ + size_t cmd_end = equals; + while (cmd_end > 0 && iswspace(line.at(cmd_end - 1))) + cmd_end--; + + /* See if this command matches */ + if (line.compare(0, cmd_end, src) == 0) + { + /* Success. Set output to everythign past the end of the string. */ + if (output != NULL) + output->assign(line, equals + 1, wcstring::npos); + + result = true; + break; + } + } + return result; +} diff --git a/expand.h b/expand.h index 1968e0ee5..51e149dfe 100644 --- a/expand.h +++ b/expand.h @@ -206,6 +206,10 @@ void expand_variable_error(parser_t &parser, const wchar_t *token, size_t token_ */ std::vector expand_get_all_process_names(void); +/** Abbreviation support. Expand src as an abbreviation, returning true if one was found, false if not. If result is not-null, returns the abbreviation by reference. */ +#define USER_ABBREVIATIONS_VARIABLE_NAME L"fish_user_abbreviations" +bool expand_abbreviation(const wcstring &src, wcstring *output); + /* Terrible hacks */ bool fish_xdm_login_hack_hack_hack_hack(std::vector *cmds, int argc, const char * const *argv); bool fish_openSUSE_dbus_hack_hack_hack_hack(std::vector *args); diff --git a/fish_tests.cpp b/fish_tests.cpp index fad9b7ecb..bbcd35c38 100644 --- a/fish_tests.cpp +++ b/fish_tests.cpp @@ -703,6 +703,67 @@ static void test_fuzzy_match(void) if (string_fuzzy_match_string(L"BB", L"ALPHA!").type != fuzzy_match_none) err(L"test_fuzzy_match failed on line %ld", __LINE__); } +static void test_abbreviations(void) +{ + say(L"Testing abbreviations"); + + const wchar_t *buff = L"echo (echo (echo (gc"; + size_t cursor_pos = wcslen(buff) - 2; + const wchar_t *cmdsub_begin = NULL, *cmdsub_end = NULL; + parse_util_cmdsubst_extent(buff, cursor_pos, &cmdsub_begin, &cmdsub_end); + assert(cmdsub_begin != NULL && cmdsub_begin >= buff); + assert(cmdsub_end != NULL && cmdsub_end >= cmdsub_begin); + fprintf(stderr, "cmdsub of '%ls' at %lu is '%ls'\n", buff, cursor_pos, wcstring(cmdsub_begin, cmdsub_end).c_str()); + exit(0); + + const wchar_t *abbreviations = + L"gc=git checkout" ARRAY_SEP_STR + L"foo=" ARRAY_SEP_STR + L"gc=something else" ARRAY_SEP_STR + L"=" ARRAY_SEP_STR + L"=foo" ARRAY_SEP_STR + L"foo" ARRAY_SEP_STR + L"foo=bar"; + + env_push(true); + + int ret = env_set(USER_ABBREVIATIONS_VARIABLE_NAME, abbreviations, ENV_LOCAL); + if (ret != 0) err(L"Unable to set abbreviation variable"); + + wcstring result; + if (expand_abbreviation(L"", &result)) err(L"Unexpected success with empty abbreviation"); + if (expand_abbreviation(L"nothing", &result)) err(L"Unexpected success with missing abbreviation"); + + if (! expand_abbreviation(L"gc", &result)) err(L"Unexpected failure with gc abbreviation"); + if (result != L"git checkout") err(L"Wrong abbreviation result for gc"); + result.clear(); + + if (! expand_abbreviation(L"foo", &result)) err(L"Unexpected failure with foo abbreviation"); + if (result != L"bar") err(L"Wrong abbreviation result for foo"); + + bool expanded; + expanded = reader_expand_abbreviation_in_command(L"just a command", wcslen(L"just "), &result); + if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__); + expanded = reader_expand_abbreviation_in_command(L"gc somebranch", 0, &result); + if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__); + expanded = reader_expand_abbreviation_in_command(L"gc somebranch", 1, &result); + if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__); + + expanded = reader_expand_abbreviation_in_command(L"gc somebranch", wcslen(L"gc "), &result); + if (! expanded) err(L"gc not expanded"); + if (result != L"git checkout somebranch") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str()); + + expanded = reader_expand_abbreviation_in_command(L"echo hi ; gc somebranch", wcslen(L"echo hi ; gc "), &result); + if (! expanded) err(L"gc not expanded on line %ld", (long)__LINE__); + if (result != L"echo hi ; git checkout somebranch") err(L"gc incorrectly expanded on line %ld", (long)__LINE__); + + expanded = reader_expand_abbreviation_in_command(L"echo (echo (echo (echo (gc ", wcslen(L"echo (echo (echo (echo (gc "), &result); + if (! expanded) err(L"gc not expanded on line %ld", (long)__LINE__); + if (result != L"echo (echo (git checkout ") err(L"gc incorrectly expanded on line %ld", (long)__LINE__); + + env_pop(); +} + /** Test path functions */ static void test_path() { @@ -1776,6 +1837,7 @@ int main(int argc, char **argv) test_lru(); test_expand(); test_fuzzy_match(); + test_abbreviations(); test_test(); test_path(); test_word_motion(); diff --git a/reader.cpp b/reader.cpp index 9b2eea14e..d9cb363bd 100644 --- a/reader.cpp +++ b/reader.cpp @@ -182,6 +182,8 @@ static pthread_key_t generation_count_key; /* A color is an int */ typedef int color_t; +static void set_command_line_and_position(const wcstring &new_str, size_t pos); + /** A struct describing the state of the interactive reader. These states can be stacked, in case reader_readline() calls are @@ -203,6 +205,9 @@ public: /** When backspacing, we temporarily suppress autosuggestions */ bool suppress_autosuggestion; + /** Whether abbreviations are expanded */ + bool expand_abbreviations; + /** The representation of the current screen contents */ screen_t screen; @@ -244,6 +249,9 @@ public: /** Do what we need to do whenever our command line changes */ void command_line_changed(void); + /** Expand abbreviations at the current cursor position. Returns true if the command line changed. */ + bool expand_abbreviation_as_necessary(void); + /** The current position of the cursor in buff. */ size_t buff_pos; @@ -326,6 +334,7 @@ public: reader_data_t() : allow_autosuggestion(0), suppress_autosuggestion(0), + expand_abbreviations(0), history(0), token_history_pos(0), search_pos(0), @@ -635,6 +644,148 @@ void reader_data_t::command_line_changed() s_generation_count++; } +/* Expand abbreviations at the given cursor position. Does NOT inspect 'data'. */ +bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t cursor_pos, wcstring *output) +{ + /* Can't have the cursor at the beginning */ + if (cursor_pos == 0) + return false; + + /* See if we are at "command position". Get the surrounding command substitution, and get the extent of the first token. */ + const wchar_t * const buff = cmdline.c_str(); + const wchar_t *cmdsub_begin = NULL, *cmdsub_end = NULL; + parse_util_cmdsubst_extent(buff, cursor_pos, &cmdsub_begin, &cmdsub_end); + assert(cmdsub_begin != NULL && cmdsub_begin >= buff); + assert(cmdsub_end != NULL && cmdsub_end >= cmdsub_begin); + fprintf(stderr, "cmdsub of '%ls' at %lu is '%ls'\n", cmdline.c_str(), cursor_pos, wcstring(cmdsub_begin, cmdsub_end).c_str()); + + /* Determine the offset of this command substitution */ + const size_t subcmd_offset = cmdsub_begin - buff; + + const wcstring subcmd = wcstring(cmdsub_begin, cmdsub_end - cmdsub_begin); + const wchar_t *subcmd_cstr = subcmd.c_str(); + + /* Get the token before the cursor */ + const wchar_t *subcmd_tok_begin = NULL, *subcmd_tok_end = NULL; + size_t subcmd_cursor_pos = cursor_pos + subcmd_offset; + parse_util_token_extent(subcmd_cstr, subcmd_cursor_pos, NULL, NULL, &subcmd_tok_begin, &subcmd_tok_end); + + /* Compute the offset of the token before the cursor within the subcmd */ + assert(subcmd_tok_begin >= subcmd_cstr); + assert(subcmd_tok_end >= subcmd_tok_begin); + const size_t subcmd_tok_begin_offset = subcmd_tok_begin - subcmd_cstr; + const size_t subcmd_tok_length = subcmd_tok_end - subcmd_tok_begin; + + /* Now parse the subcmd, looking for commands */ + bool had_cmd = false, previous_token_is_cmd = false; + tokenizer_t tok(subcmd_cstr, TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS); + for (; tok_has_next(&tok); tok_next(&tok)) + { + size_t tok_pos = static_cast(tok_get_pos(&tok)); + if (tok_pos > subcmd_tok_begin_offset) + { + /* We've passed the token we're interested in */ + break; + } + + int last_type = tok_last_type(&tok); + + switch (last_type) + { + case TOK_STRING: + { + if (had_cmd) + { + /* Parameter to the command. */ + } + else + { + /* Command. */ + had_cmd = true; + if (tok_pos == subcmd_tok_begin_offset) + { + /* This is the token we care about! */ + previous_token_is_cmd = true; + } + } + break; + } + + case TOK_REDIRECT_NOCLOB: + case TOK_REDIRECT_OUT: + case TOK_REDIRECT_IN: + case TOK_REDIRECT_APPEND: + case TOK_REDIRECT_FD: + { + if (!had_cmd) + { + break; + } + tok_next(&tok); + break; + } + + case TOK_PIPE: + case TOK_BACKGROUND: + case TOK_END: + { + had_cmd = false; + break; + } + + case TOK_COMMENT: + case TOK_ERROR: + default: + { + break; + } + } + } + + bool result = false; + if (previous_token_is_cmd) + { + /* The token is a command. Try expanding it as an abbreviation. */ + const wcstring token = wcstring(subcmd, subcmd_tok_begin_offset, subcmd_tok_length); + wcstring abbreviation; + if (expand_abbreviation(token, &abbreviation)) + { + /* There was an abbreviation! Replace the token in the full command. Maintain the relative position of the cursor. */ + if (output != NULL) + { + size_t cmd_tok_begin_offset = subcmd_tok_begin_offset + subcmd_offset; + output->assign(cmdline); + output->replace(cmd_tok_begin_offset, subcmd_tok_length, abbreviation); + } + result = true; + } + } + return result; +} + +/* Expand abbreviations */ +bool reader_data_t::expand_abbreviation_as_necessary(void) +{ + bool result = false; + if (this->expand_abbreviations) + { + wcstring new_cmdline; + if (reader_expand_abbreviation_in_command(this->command_line, this->buff_pos, &new_cmdline)) + { + /* We expanded an abbreviation! The cursor moves by the difference in the command line lengths. */ + size_t new_buff_pos = this->buff_pos + new_cmdline.size() - this->command_line.size(); + + this->command_line.swap(new_cmdline); + data->command_line_changed(); + data->buff_pos = new_buff_pos; + reader_super_highlight_me_plenty(data->buff_pos); + reader_repaint(); + + result = true; + } + } + return result; +} /** Sorts and remove any duplicate completions in the list. */ static void sort_and_make_unique(std::vector &l) @@ -1980,8 +2131,7 @@ void reader_sanity_check() } /** - Set the specified string from the history as the current buffer. Do - not modify prefix_width. + Set the specified string as the current buffer. */ static void set_command_line_and_position(const wcstring &new_str, size_t pos) { @@ -2462,6 +2612,11 @@ void reader_set_allow_autosuggesting(bool flag) data->allow_autosuggestion = flag; } +void reader_set_expand_abbreviations(bool flag) +{ + data->expand_abbreviations = flag; +} + void reader_set_complete_function(complete_function_t f) { data->complete_func = f; @@ -2712,6 +2867,7 @@ static int read_i(void) reader_set_highlight_function(&highlight_shell); reader_set_test_function(&reader_shell_test); reader_set_allow_autosuggesting(true); + reader_set_expand_abbreviations(true); reader_import_history_if_necessary(); parser_t &parser = parser_t::principal_parser(); @@ -2851,7 +3007,6 @@ const wchar_t *reader_readline(void) data->search_buff.clear(); data->search_mode = NO_SEARCH; - exec_prompt(); reader_super_highlight_me_plenty(data->buff_pos); @@ -3261,7 +3416,19 @@ const wchar_t *reader_readline(void) } } - switch (data->test_func(data->command_line.c_str())) + /* See if this command is valid */ + int command_test_result = data->test_func(data->command_line.c_str()); + if (command_test_result == 0) + { + /* This command is valid, but an abbreviation may make it invalid. If so, we will have to test again. */ + bool abbreviation_expanded = data->expand_abbreviation_as_necessary(); + if (abbreviation_expanded) + { + command_test_result = data->test_func(data->command_line.c_str()); + } + } + + switch (command_test_result) { case 0: diff --git a/reader.h b/reader.h index dfe8d1ed5..0ead2aa40 100644 --- a/reader.h +++ b/reader.h @@ -204,6 +204,10 @@ void reader_set_right_prompt(const wcstring &prompt); /** Sets whether autosuggesting is allowed. */ void reader_set_allow_autosuggesting(bool flag); +/** Sets whether abbreviation expansion is performed. */ +void reader_set_expand_abbreviations(bool flag); + + /** Sets whether the reader should exit on ^C. */ void reader_set_exit_on_interrupt(bool flag); @@ -243,6 +247,9 @@ int reader_search_mode(); /* Given a command line and an autosuggestion, return the string that gets shown to the user. Exposed for testing purposes only. */ wcstring combine_command_and_autosuggestion(const wcstring &cmdline, const wcstring &autosuggestion); +/* Expand abbreviations at the given cursor position. Exposed for testing purposes only. */ +bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t cursor_pos, wcstring *output); + /* Apply a completion string. Exposed for testing only. */ wcstring completion_apply_to_command_line(const wcstring &val_str, complete_flags_t flags, const wcstring &command_line, size_t *inout_cursor_pos, bool append_only); From f9c2a77c67754324f3036ec79501c6131d19562b Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 17 Jul 2013 02:55:15 -0700 Subject: [PATCH 25/25] Next stab at abbreviations. Highlighting should work. --- fish_tests.cpp | 42 ++++++++++++++---------------- highlight.cpp | 3 +++ parse_util.cpp | 4 --- reader.cpp | 69 ++++++++++++++++++++++++++++++-------------------- 4 files changed, 64 insertions(+), 54 deletions(-) diff --git a/fish_tests.cpp b/fish_tests.cpp index bbcd35c38..41464c31a 100644 --- a/fish_tests.cpp +++ b/fish_tests.cpp @@ -535,21 +535,19 @@ static void test_utils() const wchar_t *begin = NULL, *end = NULL; parse_util_cmdsubst_extent(a, 0, &begin, &end); - if (begin != a || end - begin != wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); parse_util_cmdsubst_extent(a, 1, &begin, &end); - if (begin != a || end - begin != wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); parse_util_cmdsubst_extent(a, 2, &begin, &end); - if (begin != a || end - begin != wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); parse_util_cmdsubst_extent(a, 3, &begin, &end); - if (begin != a || end - begin != wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); + if (begin != a || end != begin + wcslen(begin)) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); parse_util_cmdsubst_extent(a, 8, &begin, &end); if (begin != a + wcslen(L"echo (")) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); parse_util_cmdsubst_extent(a, 17, &begin, &end); if (begin != a + wcslen(L"echo (echo (")) err(L"parse_util_cmdsubst_extent failed on line %ld", (long)__LINE__); - - } class lru_node_test_t : public lru_node_t @@ -707,15 +705,6 @@ static void test_abbreviations(void) { say(L"Testing abbreviations"); - const wchar_t *buff = L"echo (echo (echo (gc"; - size_t cursor_pos = wcslen(buff) - 2; - const wchar_t *cmdsub_begin = NULL, *cmdsub_end = NULL; - parse_util_cmdsubst_extent(buff, cursor_pos, &cmdsub_begin, &cmdsub_end); - assert(cmdsub_begin != NULL && cmdsub_begin >= buff); - assert(cmdsub_end != NULL && cmdsub_end >= cmdsub_begin); - fprintf(stderr, "cmdsub of '%ls' at %lu is '%ls'\n", buff, cursor_pos, wcstring(cmdsub_begin, cmdsub_end).c_str()); - exit(0); - const wchar_t *abbreviations = L"gc=git checkout" ARRAY_SEP_STR L"foo=" ARRAY_SEP_STR @@ -742,24 +731,31 @@ static void test_abbreviations(void) if (result != L"bar") err(L"Wrong abbreviation result for foo"); bool expanded; - expanded = reader_expand_abbreviation_in_command(L"just a command", wcslen(L"just "), &result); + expanded = reader_expand_abbreviation_in_command(L"just a command", 3, &result); if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__); expanded = reader_expand_abbreviation_in_command(L"gc somebranch", 0, &result); - if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__); - expanded = reader_expand_abbreviation_in_command(L"gc somebranch", 1, &result); - if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__); + if (! expanded) err(L"Command not expanded on line %ld", (long)__LINE__); - expanded = reader_expand_abbreviation_in_command(L"gc somebranch", wcslen(L"gc "), &result); + expanded = reader_expand_abbreviation_in_command(L"gc somebranch", wcslen(L"gc"), &result); if (! expanded) err(L"gc not expanded"); if (result != L"git checkout somebranch") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str()); - expanded = reader_expand_abbreviation_in_command(L"echo hi ; gc somebranch", wcslen(L"echo hi ; gc "), &result); + expanded = reader_expand_abbreviation_in_command(L"echo hi ; gc somebranch", wcslen(L"echo hi ; g"), &result); if (! expanded) err(L"gc not expanded on line %ld", (long)__LINE__); if (result != L"echo hi ; git checkout somebranch") err(L"gc incorrectly expanded on line %ld", (long)__LINE__); - expanded = reader_expand_abbreviation_in_command(L"echo (echo (echo (echo (gc ", wcslen(L"echo (echo (echo (echo (gc "), &result); + expanded = reader_expand_abbreviation_in_command(L"echo (echo (echo (echo (gc ", wcslen(L"echo (echo (echo (echo (gc"), &result); if (! expanded) err(L"gc not expanded on line %ld", (long)__LINE__); - if (result != L"echo (echo (git checkout ") err(L"gc incorrectly expanded on line %ld", (long)__LINE__); + if (result != L"echo (echo (echo (echo (git checkout ") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str()); + + /* if commands should be expanded */ + expanded = reader_expand_abbreviation_in_command(L"if gc", wcslen(L"if gc"), &result); + if (! expanded) err(L"gc not expanded on line %ld", (long)__LINE__); + if (result != L"if git checkout") err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str()); + + /* others should not be */ + expanded = reader_expand_abbreviation_in_command(L"of gc", wcslen(L"of gc"), &result); + if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__); env_pop(); } diff --git a/highlight.cpp b/highlight.cpp index 265fd40af..606604386 100644 --- a/highlight.cpp +++ b/highlight.cpp @@ -1106,6 +1106,9 @@ static void tokenize(const wchar_t * const buff, std::vector &color, const if (! is_cmd && use_function) is_cmd = function_exists_no_autoload(cmd, vars); + if (! is_cmd) + is_cmd = expand_abbreviation(cmd, NULL); + /* Moving on to expensive tests */ diff --git a/parse_util.cpp b/parse_util.cpp index e6d04a3f9..5e6f4459b 100644 --- a/parse_util.cpp +++ b/parse_util.cpp @@ -541,7 +541,6 @@ void parse_util_set_argv(const wchar_t * const *argv, const wcstring_list_t &nam { const wchar_t * const *arg; size_t i; - for (i=0, arg=argv; i < named_arguments.size(); i++) { env_set(named_arguments.at(i).c_str(), *arg, ENV_LOCAL); @@ -549,10 +548,7 @@ void parse_util_set_argv(const wchar_t * const *argv, const wcstring_list_t &nam if (*arg) arg++; } - - } - } wchar_t *parse_util_unescape_wildcards(const wchar_t *str) diff --git a/reader.cpp b/reader.cpp index d9cb363bd..8febb7994 100644 --- a/reader.cpp +++ b/reader.cpp @@ -97,8 +97,8 @@ commence. #include "iothread.h" #include "intern.h" #include "path.h" - #include "parse_util.h" +#include "parser_keywords.h" /** Maximum length of prefix string when printing completion @@ -249,8 +249,8 @@ public: /** Do what we need to do whenever our command line changes */ void command_line_changed(void); - /** Expand abbreviations at the current cursor position. Returns true if the command line changed. */ - bool expand_abbreviation_as_necessary(void); + /** Expand abbreviations at the current cursor position. */ + bool expand_abbreviation_as_necessary(); /** The current position of the cursor in buff. */ size_t buff_pos; @@ -647,17 +647,12 @@ void reader_data_t::command_line_changed() /* Expand abbreviations at the given cursor position. Does NOT inspect 'data'. */ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t cursor_pos, wcstring *output) { - /* Can't have the cursor at the beginning */ - if (cursor_pos == 0) - return false; - /* See if we are at "command position". Get the surrounding command substitution, and get the extent of the first token. */ const wchar_t * const buff = cmdline.c_str(); const wchar_t *cmdsub_begin = NULL, *cmdsub_end = NULL; parse_util_cmdsubst_extent(buff, cursor_pos, &cmdsub_begin, &cmdsub_end); assert(cmdsub_begin != NULL && cmdsub_begin >= buff); assert(cmdsub_end != NULL && cmdsub_end >= cmdsub_begin); - fprintf(stderr, "cmdsub of '%ls' at %lu is '%ls'\n", cmdline.c_str(), cursor_pos, wcstring(cmdsub_begin, cmdsub_end).c_str()); /* Determine the offset of this command substitution */ const size_t subcmd_offset = cmdsub_begin - buff; @@ -667,8 +662,9 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso /* Get the token before the cursor */ const wchar_t *subcmd_tok_begin = NULL, *subcmd_tok_end = NULL; - size_t subcmd_cursor_pos = cursor_pos + subcmd_offset; - parse_util_token_extent(subcmd_cstr, subcmd_cursor_pos, NULL, NULL, &subcmd_tok_begin, &subcmd_tok_end); + assert(cursor_pos >= subcmd_offset); + size_t subcmd_cursor_pos = cursor_pos - subcmd_offset; + parse_util_token_extent(subcmd_cstr, subcmd_cursor_pos, &subcmd_tok_begin, &subcmd_tok_end, NULL, NULL); /* Compute the offset of the token before the cursor within the subcmd */ assert(subcmd_tok_begin >= subcmd_cstr); @@ -700,12 +696,29 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso } else { - /* Command. */ - had_cmd = true; - if (tok_pos == subcmd_tok_begin_offset) + const wcstring potential_cmd = tok_last(&tok); + if (parser_keywords_is_subcommand(potential_cmd)) { - /* This is the token we care about! */ - previous_token_is_cmd = true; + if (potential_cmd == L"command" || potential_cmd == L"builtin") + { + /* 'command' and 'builtin' defeat abbreviation expansion. Skip this command. */ + had_cmd = true; + } + else + { + /* Other subcommand. Pretend it doesn't exist so that we can expand the following command */ + had_cmd = false; + } + } + else + { + /* It's a normal command */ + had_cmd = true; + if (tok_pos == subcmd_tok_begin_offset) + { + /* This is the token we care about! */ + previous_token_is_cmd = true; + } } } break; @@ -763,12 +776,13 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso return result; } -/* Expand abbreviations */ -bool reader_data_t::expand_abbreviation_as_necessary(void) +/* Expand abbreviations. This may change the command line but does NOT repaint it. This is to allow the caller to coalesce repaints. */ +bool reader_data_t::expand_abbreviation_as_necessary() { bool result = false; if (this->expand_abbreviations) { + /* Try expanding abbreviations */ wcstring new_cmdline; if (reader_expand_abbreviation_in_command(this->command_line, this->buff_pos, &new_cmdline)) { @@ -776,11 +790,8 @@ bool reader_data_t::expand_abbreviation_as_necessary(void) size_t new_buff_pos = this->buff_pos + new_cmdline.size() - this->command_line.size(); this->command_line.swap(new_cmdline); - data->command_line_changed(); data->buff_pos = new_buff_pos; - reader_super_highlight_me_plenty(data->buff_pos); - reader_repaint(); - + data->command_line_changed(); result = true; } } @@ -3418,12 +3429,14 @@ const wchar_t *reader_readline(void) /* See if this command is valid */ int command_test_result = data->test_func(data->command_line.c_str()); - if (command_test_result == 0) + if (command_test_result == 0 || command_test_result == PARSER_TEST_INCOMPLETE) { /* This command is valid, but an abbreviation may make it invalid. If so, we will have to test again. */ bool abbreviation_expanded = data->expand_abbreviation_as_necessary(); if (abbreviation_expanded) { + /* It's our reponsibility to rehighlight and repaint. But everything we do below triggers a repaint. */ + reader_super_highlight_me_plenty(data->buff_pos); command_test_result = data->test_func(data->command_line.c_str()); } } @@ -3764,9 +3777,14 @@ const wchar_t *reader_readline(void) /* Other, if a normal character, we add it to the command */ default: { - if ((!wchar_private(c)) && (((c>31) || (c==L'\n'))&& (c != 127))) { + /* Expand abbreviations on space */ + if (c == L' ') + { + data->expand_abbreviation_as_necessary(); + } + /* Regular character */ insert_char(c); } @@ -3800,10 +3818,7 @@ const wchar_t *reader_readline(void) } writestr(L"\n"); - /* - if( comp ) - halloc_free( comp ); - */ + if (!reader_exit_forced()) { if (tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */