Skip to content

Commit b71b641

Browse files
committed
Post-prompt command
1 parent c7cbd75 commit b71b641

15 files changed

+124
-13
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ History of Yash
22

33
## Yash 2.57 (Unreleased)
44

5+
- Added support for the "$POST_PROMPT_COMMAND" variable, whose value
6+
is executed after reading a command line in the interactive shell.
57
- [line-editing] Fixed the spurious error message printed when
68
completing after `git config alias.` with the nounset shell option
79
enabled.

NEWS.ja

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ Yash 更新履歴
22

33
## Yash 2.57 (未リリース)
44

5+
- "$POST_PROMPT_COMMAND" に対応。対話モードでコマンドを読むごとに
6+
変数の値が実行される
57
- [行編集] nounset オプション有効時に `git config alias.` に続けて
68
補完をしようとするとエラーが出るのを修正
79
- [行編集] カーソルがバックスラッシュの直後にある時に補完をすると

doc/_set.txt

+1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ This option enables the link:posix.html[POSIXly-correct mode].
202202
When this option is disabled, the <<so-xtrace,x-trace option>> is temporarily
203203
disabled while the shell is executing commands defined in the
204204
link:params.html#sv-command_not_found_handler[+COMMAND_NOT_FOUND_HANDLER+],
205+
link:params.html#sv-post_prompt_command[+POST_PROMPT_COMMAND+],
205206
link:params.html#sv-prompt_command[+PROMPT_COMMAND+], or
206207
link:params.html#sv-yash_after_cd[+YASH_AFTER_CD+] variable.
207208

doc/interact.txt

+10-3
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,16 @@ variables can be defined with a name prefixed with +YASH_+ (e.g.
178178
link:params.html#sv-yash_ps1[+YASH_PS1+]). This allows using a different
179179
prompt string than that in the POSIXly-correct mode.
180180

181-
When the shell is not in the link:posix.html[POSIXly-correct mode],
182-
the value of the link:params.html#sv-prompt_command[+PROMPT_COMMAND+ variable]
183-
is executed before each prompt.
181+
When the shell is not in the link:posix.html[POSIXly-correct mode]:
182+
183+
- The value of the link:params.html#sv-prompt_command[+PROMPT_COMMAND+ variable]
184+
is executed before each prompt.
185+
- The value of the
186+
link:params.html#sv-post_prompt_command[+POST_PROMPT_COMMAND+ variable] is
187+
executed after each line is input. While the execution, the
188+
link:params.html#sv-command[+COMMAND+ variable] is set to the just input
189+
line. You can even modify the variable to manipulate the command to be
190+
executed. If you unset the variable, the command will not be executed.
184191

185192
[[history]]
186193
== Command history

doc/ja/_set.txt

+1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ link:syntax.html#for[For ループ]が{zwsp}link:exec.html#function[関数]の
134134
[[so-traceall]]trace-all::
135135
このオプションは、補助コマンド実行中も <<so-xtrace,x-trace オプション>>を機能させるかどうかを指定します。補助コマンドとは、
136136
link:params.html#sv-command_not_found_handler[+COMMAND_NOT_FOUND_HANDLER+]、
137+
link:params.html#sv-post_prompt_command[+POST_PROMPT_COMMAND+]、
137138
link:params.html#sv-prompt_command[+PROMPT_COMMAND+]、および
138139
link:params.html#sv-yash_after_cd[+YASH_AFTER_CD+]
139140
変数の値として定義され、特定のタイミングで解釈・実行されるコマンドです。

doc/ja/interact.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ link:lineedit.html#prediction[コマンドライン推定]を使用している
9898

9999
link:posix.html[POSIX 準拠モード]でないときは、上記の変数は名前に +YASH_+ を付けた名前 (例えば link:params.html#sv-yash_ps1[+YASH_PS1+]) で定義することもできます。これにより、POSIX 準拠モードとは異なるプロンプトを使い分けることができます。
100100

101-
link:posix.html[POSIX 準拠モード]でないときは、プロンプトを出す前に link:params.html#sv-prompt_command[+PROMPT_COMMAND+ 変数]の値がコマンドとして実行されます。
101+
link:posix.html[POSIX 準拠モード]でないときは、以下の変数が評価されます。
102+
103+
- プロンプトを出す前に link:params.html#sv-prompt_command[+PROMPT_COMMAND+ 変数]の値がコマンドとして実行されます。
104+
- コマンドが一行分入力されるたびに link:params.html#sv-post_prompt_command[+POST_PROMPT_COMMAND+ 変数]の値がコマンドとして実行されます。実行中は入力されたコマンドが link:params.html#sv-command[+COMMAND+ 変数]に代入されます。この変数の値を変更することで実行されるコマンドを改変することもできます。変数を削除するとコマンドは実行されません。
102105

103106
[[history]]
104107
== コマンド履歴

doc/ja/params.txt

+8-1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ dfn:[変数]とはユーザが自由に代入可能なパラメータです。
8282
[[sv-columns]]+COLUMNS+::
8383
この変数は端末ウィンドウの横幅 (文字数) を指定します。この変数が設定されている場合、デフォルトの横幅ではなくこの変数の値で指定された横幅が{zwsp}link:lineedit.html[行編集]で使われます。
8484

85+
[[sv-command]]+COMMAND+::
86+
<<sv-post_prompt_command,+POST_PROMPT_COMMAND+>> 変数が実行される間、この変数は直前に入力されたコマンドを示します。
87+
+POST_PROMPT_COMMAND+ の実行が終わるとこの変数は消去されます。
88+
8589
[[sv-command_not_found_handler]]+COMMAND_NOT_FOUND_HANDLER+::
8690
シェルが実行しようとしたコマンドが見つからなかったとき、この変数の値がコマンドとして実行されます。不明なコマンドを実行したときに何か別のコマンドを実行させたい時に便利です。{zwsp}link:exec.html#simple[単純コマンドの実行]を参照。
8791
+
@@ -163,11 +167,14 @@ link:_getopts.html[Getopts 組込みコマンド]で引数付きのオプショ
163167
[[sv-path]]+PATH+::
164168
この変数は、{zwsp}link:exec.html#search[コマンドの検索時]にコマンドのありかを示すパスを指定します。
165169

170+
[[sv-post_prompt_command]]+POST_PROMPT_COMMAND+::
171+
link:posix.html[POSIX 準拠モード]でない{zwsp}link:interact.html[対話モード]のシェルにおいて、シェルがコマンドを一行読み込むたびに、この変数の値がコマンドとして解釈・実行されます。詳細は{zwsp}link:interact.html#prompt[プロンプト]を参照してください。
172+
166173
[[sv-ppid]]+PPID+::
167174
この変数の値は、シェルの親プロセスのプロセス ID を表す正の整数です。この変数はシェルの起動時に初期化されます。この変数の値は{zwsp}link:exec.html#subshell[サブシェル]においても変わりません。
168175

169176
[[sv-prompt_command]]+PROMPT_COMMAND+::
170-
link:posix.html[POSIX 準拠モード]でない{zwsp}link:interact.html[対話モード]のシェルにおいて、シェルが各コマンドのプロンプトを出す直前に、この変数の値がコマンドとして解釈・実行されます。これは、プロンプトを出す直前に毎回
177+
link:posix.html[POSIX 準拠モード]でない{zwsp}link:interact.html[対話モード]のシェルにおいて、シェルが各コマンドの{zwsp}link:interact.html#prompt[プロンプト]を出す直前に、この変数の値がコマンドとして解釈・実行されます。これは、プロンプトを出す直前に毎回
171178
ifdef::basebackend-html[]
172179
pass:[<code><a href="_eval.html">eval</a> -i -- "${PROMPT_COMMAND-}"</code>]
173180
endif::basebackend-html[]

doc/ja/posix.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ POSIX 準拠モードを有効にすると、yash は POSIX の規定にでき
3535
- link:builtin.html#types[任意組込みコマンドおよび拡張組込みコマンド]は実行できません。
3636
- いくつかの{zwsp}link:builtin.html[組込みコマンド]で特定のオプションが使えなくなるなど挙動が変わります。特に、長いオプションは使えなくなります。
3737
- link:interact.html[対話モード]でないとき、{zwsp}link:builtin.html#types[特殊組込みコマンド]のオプションやオペランドの使い方が間違っているとシェルは直ちに終了します。また特殊組込みコマンドで代入エラーやリダイレクトエラーが発生したときも直ちに終了します。
38-
- link:interact.html[対話モード]のプロンプトを出す前に link:params.html#sv-prompt_command[+PROMPT_COMMAND+ 変数]の値を実行しません。{zwsp}link:params.html#sv-ps1[+PS1+ 変数]・{zwsp}link:params.html#sv-ps2[+PS2+ 変数]・{zwsp}link:params.html#sv-ps4[+PS4+ 変数]の値の解釈の仕方が違います。{zwsp}link:params.html#sv-yash_ps1[+YASH_PS1+] など +YASH_+ で始まる名前のプロンプト変数は使用されません。
38+
- link:interact.html[対話モード]のプロンプトを出す前後に link:params.html#sv-prompt_command[+PROMPT_COMMAND+ 変数]および link:params.html#sv-post_prompt_command[+POST_PROMPT_COMMAND+ 変数]の値を実行しません。{zwsp}link:params.html#sv-ps1[+PS1+ 変数]・{zwsp}link:params.html#sv-ps2[+PS2+ 変数]・{zwsp}link:params.html#sv-ps4[+PS4+ 変数]の値の解釈の仕方が違います。{zwsp}link:params.html#sv-yash_ps1[+YASH_PS1+] など +YASH_+ で始まる名前のプロンプト変数は使用されません。
3939
- link:interact.html#mailcheck[メールチェック]において、ファイルが更新されている場合はファイルが空でも新着メールメッセージを出力します。
4040
4141
// vim: set filetype=asciidoc expandtab:

doc/params.txt

+12-1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ This variable specifies the width (the number of character columns) of the
145145
terminal screen. The value affects the display of
146146
link:lineedit.html[line-editing].
147147

148+
[[sv-command]]+COMMAND+::
149+
While a <<sv-post_prompt_command,post-prompt command>> is being executed,
150+
this variable is set to the just input command line. It will be unset after
151+
the post-prompt command finishes.
152+
148153
[[sv-command_not_found_handler]]+COMMAND_NOT_FOUND_HANDLER+::
149154
When the shell cannot find a command to be executed,
150155
the value of this variable is interpreted and executed instead.
@@ -284,6 +289,12 @@ This variable is initialized to +1+ when the shell is started.
284289
This variable specifies paths that are searched for a command in
285290
link:exec.html#search[command search].
286291

292+
[[sv-post_prompt_command]]+POST_PROMPT_COMMAND+::
293+
The shell interprets and executes the value of this variable after reading
294+
each command if the shell is link:interact.html[interactive] and not in
295+
the link:posix.html[POSIXly-correct mode].
296+
See link:interact.html#prompt[Prompts] for details.
297+
287298
[[sv-ppid]]+PPID+::
288299
The value of this variable is the process ID of the shell's parent process,
289300
which is a positive integer.
@@ -293,7 +304,7 @@ link:exec.html#subshell[subshell].
293304

294305
[[sv-prompt_command]]+PROMPT_COMMAND+::
295306
The shell interprets and executes the value of this variable before printing
296-
each command prompt if the shell is link:interact.html[interactive] and not in
307+
each command link:interact.html#prompt[prompt] if the shell is link:interact.html[interactive] and not in
297308
the link:posix.html[POSIXly-correct mode].
298309
This behavior is equivalent to executing the command
299310
ifdef::basebackend-html[]

doc/posix.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ When the POSIXly-correct mode is enabled:
8787
arguments or when an error occurs in assignment or redirection with a
8888
special built-in.
8989
- An link:interact.html[interactive] shell does not execute the
90-
link:params.html#sv-prompt_command[+PROMPT_COMMAND+ variable] before
91-
printing a prompt.
90+
link:params.html#sv-prompt_command[+PROMPT_COMMAND+] or
91+
link:params.html#sv-post_prompt_command[+POST_PROMPT_COMMAND+ variable]
92+
before and after a prompt, respectively.
9293
The values of the link:params.html#sv-ps1[+PS1+],
9394
link:params.html#sv-ps2[+PS2+], and link:params.html#sv-ps4[+PS4+] variables
9495
are parsed differently.

input.c

+37
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ static wchar_t *expand_ps1_posix(wchar_t *s)
6464
__attribute__((nonnull,malloc,warn_unused_result));
6565
static inline wchar_t get_euid_marker(void)
6666
__attribute__((pure));
67+
static wchar_t *post_prompt_command(wchar_t *line)
68+
__attribute__((nonnull,malloc,warn_unused_result));
6769

6870
/* An input function that inputs from a wide string.
6971
* `inputinfo' must be a pointer to a `struct input_wcs_info_T'.
@@ -288,6 +290,8 @@ inputresult_T input_interactive(struct xwcsbuf_T *buf, void *inputinfo)
288290
#endif
289291
if (info->prompttype == 1)
290292
info->prompttype = 2;
293+
if (!posixly_correct)
294+
line = post_prompt_command(line);
291295
#if YASH_ENABLE_HISTORY
292296
add_history(line);
293297
#endif
@@ -481,6 +485,39 @@ wchar_t get_euid_marker(void)
481485
return geteuid() == 0 ? L'#' : L'$';
482486
}
483487

488+
/* Executes $POST_PROMPT_COMMAND, if any.
489+
* `line' is the just input command line, which will be assigned to $COMMAND
490+
* during the execution. The post-prompt command may modify or unset the
491+
* variable. The final value of the variable is returned as a newly malloced
492+
* string. `line' is freed in this function. */
493+
wchar_t *post_prompt_command(wchar_t *line)
494+
{
495+
// If `line` ends with a newline, trim it here and append it back later.
496+
size_t linelen = wcslen(line);
497+
bool newline = linelen > 0 && line[linelen - 1] == L'\n';
498+
if (newline)
499+
line[linelen - 1] = L'\0';
500+
501+
open_new_environment(false);
502+
set_positional_parameters((void *[]) { NULL });
503+
set_variable(L VAR_COMMAND, line, SCOPE_LOCAL, false);
504+
505+
exec_variable_as_auxiliary_(VAR_POST_PROMPT_COMMAND);
506+
const wchar_t *c = getvar(L VAR_COMMAND);
507+
if (c == NULL)
508+
c = L"";
509+
510+
xwcsbuf_T linebuf;
511+
wb_init(&linebuf);
512+
wb_cat(&linebuf, c);
513+
if (newline)
514+
wb_wccat(&linebuf, L'\n');
515+
516+
close_current_environment();
517+
518+
return wb_towcs(&linebuf);
519+
}
520+
484521
/* Unsets O_NONBLOCK flag of the specified file descriptor.
485522
* If `fd' is negative, does nothing.
486523
* Returns true if successful. On error, `errno' is set and false is returned.*/

share/initialization/common

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ export SHLVL
199199
# initialize event handlers
200200
COMMAND_NOT_FOUND_HANDLER=()
201201
PROMPT_COMMAND=()
202+
POST_PROMPT_COMMAND=()
202203
YASH_AFTER_CD=()
203204

204205
# define prompt

tests/prompt-y.tst

+36
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ $
102102
$
103103
__ERR__
104104

105+
test_Oe 'POST_PROMPT_COMMAND is ignored in POSIX mode' -i +m
106+
POST_PROMPT_COMMAND='echo not printed'; echo >&2
107+
echo >&2; exit
108+
__IN__
109+
$
110+
$
111+
__ERR__
112+
105113
)
106114

107115
test_e 'YASH_PSx precedes PSx (non-POSIX)' -i +m
@@ -193,6 +201,34 @@ $
193201
123$ 1
194202
__ERR__
195203

204+
test_oe 'value of $COMMAND in post-prompt command' -i +m
205+
POST_PROMPT_COMMAND='printf "[%s]\n" "$COMMAND" >&2'
206+
echo foo\
207+
bar; exit
208+
__IN__
209+
foobar
210+
__OUT__
211+
$ $ [echo foo\]
212+
> [bar; exit]
213+
__ERR__
214+
215+
test_o 'modifying $COMMAND in post-prompt command' -i +m
216+
POST_PROMPT_COMMAND='COMMAND="$COMMAND; echo post"'
217+
echo foo
218+
exit
219+
__IN__
220+
foo
221+
post
222+
__OUT__
223+
224+
test_O 'unsetting $COMMAND in post-prompt command' -i +m
225+
POST_PROMPT_COMMAND='if [ "$COMMAND" != exit ]; then unset COMMAND; fi'
226+
echo foo\
227+
bar
228+
exit
229+
echo not reached
230+
__IN__
231+
196232
test_e '\$ in PS1 and PS2 (non-root)' -i +m
197233
PS1='\$ ' PS2='\$_'; echo >&2
198234
e\

tests/run-test.sh

+3-3
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ exec >|"${test_file%.*}.trs"
7777
export LC_CTYPE="${LC_ALL-${LC_CTYPE-$LANG}}"
7878
export LANG=C
7979
export YASH_LOADPATH= # ignore default yashrc
80-
unset -v CDPATH COLUMNS COMMAND_NOT_FOUND_HANDLER DIRSTACK ECHO_STYLE ENV
81-
unset -v FCEDIT HANDLED HISTFILE HISTRMDUP HISTSIZE HOME IFS LC_ALL
80+
unset -v CDPATH COLUMNS COMMAND COMMAND_NOT_FOUND_HANDLER DIRSTACK ECHO_STYLE
81+
unset -v ENV FCEDIT HANDLED HISTFILE HISTRMDUP HISTSIZE HOME IFS LC_ALL
8282
unset -v LC_COLLATE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LINES MAIL
83-
unset -v MAILCHECK MAILPATH NLSPATH OLDPWD PROMPT_COMMAND
83+
unset -v MAILCHECK MAILPATH NLSPATH OLDPWD POST_PROMPT_COMMAND PROMPT_COMMAND
8484
unset -v PS1 PS1R PS1S PS2 PS2R PS2S PS3 PS3R PS3S PS4 PS4R PS4S
8585
unset -v RANDOM TERM YASH_AFTER_CD YASH_LE_TIMEOUT YASH_VERSION
8686
unset -v A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _

variable.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* Yash: yet another shell */
22
/* variable.h: deals with shell variables and parameters */
3-
/* (C) 2007-2020 magicant */
3+
/* (C) 2007-2024 magicant */
44

55
/* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@ extern char **environ;
2828
/* variable names */
2929
#define VAR_CDPATH "CDPATH"
3030
#define VAR_COLUMNS "COLUMNS"
31+
#define VAR_COMMAND "COMMAND"
3132
#define VAR_COMMAND_NOT_FOUND_HANDLER "COMMAND_NOT_FOUND_HANDLER"
3233
#define VAR_DIRSTACK "DIRSTACK"
3334
#define VAR_ECHO_STYLE "ECHO_STYLE"
@@ -57,6 +58,7 @@ extern char **environ;
5758
#define VAR_OPTARG "OPTARG"
5859
#define VAR_OPTIND "OPTIND"
5960
#define VAR_PATH "PATH"
61+
#define VAR_POST_PROMPT_COMMAND "POST_PROMPT_COMMAND"
6062
#define VAR_PPID "PPID"
6163
#define VAR_PROMPT_COMMAND "PROMPT_COMMAND"
6264
#define VAR_PS1 "PS1"

0 commit comments

Comments
 (0)