diff --git a/man/icewm-preferences.pod b/man/icewm-preferences.pod index f10a0613e..633bd72b2 100644 --- a/man/icewm-preferences.pod +++ b/man/icewm-preferences.pod @@ -1201,6 +1201,13 @@ Dimension of the large icons. Dimension of the large icons. +=item B="nohup|(nice[[:space:]]+-n[[:space:]]*[[:digit:]]+)|sudo|(LANG|LC_[[:alnum:]]]*)(=|=[^[:space:]]+)" + +Regular expression (POSIX Extended flavor) which marks the begin of a +command line in command input fields. Such prefixes are ignored while +the auto-completion action is performed, typically for commands acting +as pass-through wrapper, executing the specified command. + =item B=3 [0-64] Horizontal margin of the quickswitch window. diff --git a/src/default.h b/src/default.h index a5f6c32f5..2c37b5bf6 100644 --- a/src/default.h +++ b/src/default.h @@ -240,6 +240,8 @@ XSV(const char *, fmtTimeAlt, NULL) XSV(const char *, fmtDate, "%Y-%m-%d %H:%M:%S %z %B %A") #endif +XSV(const char *, inputIgnorePfx, "nohup|(nice[[:space:]]+-n[[:space:]]*[[:digit:]]+)|sudo|(LANG|LC_[[:alnum:]]]*)(=|=[^[:space:]]+)") + #ifdef CFGDEF cfoption icewm_preferences[] = { @@ -574,6 +576,8 @@ cfoption icewm_preferences[] = { OKF("WorkspaceNames", addWorkspace, "Add a workspace"), OKF("KeyboardLayouts", addKeyboard, "Add a keyboard layout"), OSV("WinMenuItems", &winMenuItems, "The list of items to be supported in the menu window (rmsnxfhualytieckw)"), + + OSV("InputIgnorePrefix", &inputIgnorePfx, "Prefix to ignore while tab-completing (POSIX Extended Regular Expression)"), OK0() }; diff --git a/src/yinputline.cc b/src/yinputline.cc index a1b177420..c66140c4d 100644 --- a/src/yinputline.cc +++ b/src/yinputline.cc @@ -10,6 +10,7 @@ #include "yxapp.h" #include "prefs.h" #include "intl.h" +#include "regex.h" #include class YInputMenu: public YMenu { @@ -46,16 +47,30 @@ YInputLine::YInputLine(YWindow *parent, YInputListener *listener): inputBg(&clrInput), inputFg(&clrInputText), inputSelectionBg(&clrInputSelection), - inputSelectionFg(&clrInputSelectionText) + inputSelectionFg(&clrInputSelectionText), + prefixRegex(nullptr) { addStyle(wsNoExpose); if (inputFont != null) setSize(width(), inputFont->height() + 2); + if (inputIgnorePfx && *inputIgnorePfx) { + prefixRegex = new regex_t; + mstring reFullPrefix("^(", inputIgnorePfx, ")[[:space:]]+"); + if (0 != regcomp(prefixRegex, reFullPrefix, REG_EXTENDED)) { + delete prefixRegex; + prefixRegex = nullptr; + } + } } YInputLine::~YInputLine() { if (inputContext) XDestroyIC(inputContext); + if (prefixRegex) { + regfree(prefixRegex); + delete prefixRegex; + prefixRegex = nullptr; + } } void YInputLine::setText(mstring text, bool asMarked) { @@ -762,12 +777,21 @@ void YInputLine::complete() { } } csmart res; + + mstring ignoredPfx; + if (prefixRegex) { + regmatch_t full_match; + if (0 == regexec(prefixRegex, mstr, 1, &full_match, 0)) { + ignoredPfx = mstr.substring(0, full_match.rm_eo); + mstr = mstr.substring(full_match.rm_eo); + } + } int res_count = globit_best(mstr, &res, nullptr, nullptr); // directory is not a final match if (res_count == 1 && upath(res).dirExists()) res_count++; if (1 <= res_count) - setText(mstring(res), res_count == 1); + setText(ignoredPfx + mstring(res), res_count == 1); else { int i = mstr.lastIndexOf(' '); if (i > 0 && size_t(i + 1) < mstr.length()) { @@ -776,7 +800,7 @@ void YInputLine::complete() { if (sub[0] == '$' || sub[0] == '~') { mstring exp = upath(sub).expand(); if (exp != sub && exp != null) { - setText(pre + exp, false); + setText(ignoredPfx + pre + exp, false); } else if (sub.indexOf('/') == -1) { mstring var = sub.substring(1); @@ -788,7 +812,7 @@ void YInputLine::complete() { } if (exp != var) { char doti[] = { char(sub[0]), '\0' }; - setText(pre + doti + exp, false); + setText(ignoredPfx + pre + doti + exp, false); } } } @@ -799,7 +823,7 @@ void YInputLine::complete() { if (upath::glob(sub + "*", list, "/S") && list.nonempty()) { if (list.getCount() == 1) { mstring found(mstr.substring(0, i + 1) + list[0]); - setText(found, true); + setText(ignoredPfx + found, true); } else { int len = 0; for (; list[0][len]; ++len) { @@ -813,7 +837,7 @@ void YInputLine::complete() { if (len) { mstring common(list[0], len); mstring found(mstr.substring(0, i + 1) + common); - setText(found, false); + setText(ignoredPfx + found, false); } } } @@ -822,7 +846,7 @@ void YInputLine::complete() { if (mstr[0] == '$') { mstring var = completeVariable(mstr.substring(1)); if (var != mstr.substring(1)) - setText(mstr.substring(0, 1) + var, false); + setText(ignoredPfx + mstr.substring(0, 1) + var, false); } } } diff --git a/src/yinputline.h b/src/yinputline.h index 415a1c3a9..6ef29e486 100644 --- a/src/yinputline.h +++ b/src/yinputline.h @@ -6,6 +6,8 @@ #include "ypopup.h" #include "ystring.h" +#include + class YMenu; class YInputLine; class YInputMenu; @@ -103,6 +105,7 @@ class YInputLine: YColorName inputSelectionFg; lazy cursorBlinkTimer; lazy inputMenu; + regex_t* prefixRegex; private: // not-used YInputLine(const YInputLine &);