This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: bash completion


Hi.

Some time ago, I investigated quite new feature of clang which
is support of --autocomplete argument. That can be run from bash completion
script and one gets more precise completion hints:

http://blog.llvm.org/2017/09/clang-bash-better-auto-completion-is.html
https://www.youtube.com/watch?v=zLPwPdZBpSY

I like the idea and I would describe how is that better to current GCC completion
script sitting here:
https://github.com/scop/bash-completion/blob/master/completions/gcc

1) gcc -fsanitize=^ - no support for option enum values
2) gcc -fno-sa^ - no support for negative options
3) gcc --param=^ - no support for param names

These are main limitations I see. I'm attaching working prototype, which you
can test by installed GCC, setting it on $PATH and doing:
$ source gcc.sh

Then bash completion is provided via the newly added option. Some examples:

1)
$ gcc -fsanitize=
address                    bounds                     enum                       integer-divide-by-zero     nonnull-attribute          pointer-compare            return                     shift-base                 thread                     vla-bound
alignment                  bounds-strict              float-cast-overflow        kernel-address             null                       pointer-overflow           returns-nonnull-attribute  shift-exponent             undefined                  vptr
bool                       builtin                    float-divide-by-zero       leak                       object-size                pointer-subtract           shift                      signed-integer-overflow    unreachable                

2)
$ gcc -fno-ipa-
-fno-ipa-bit-cp         -fno-ipa-cp-alignment   -fno-ipa-icf            -fno-ipa-icf-variables  -fno-ipa-profile        -fno-ipa-pure-const     -fno-ipa-reference      -fno-ipa-struct-reorg   
-fno-ipa-cp             -fno-ipa-cp-clone       -fno-ipa-icf-functions  -fno-ipa-matrix-reorg   -fno-ipa-pta            -fno-ipa-ra             -fno-ipa-sra            -fno-ipa-vrp            

3)
$ gcc --param=lto-
lto-max-partition  lto-min-partition  lto-partitions    

4)
gcc --param lto-
lto-max-partition  lto-min-partition  lto-partitions     

The patch is quite lean and if people like, I will prepare a proper
patch submission. I know about some limitations that can be then
handled incrementally.

Thoughts?
Martin
>From 7bf882961cd81d3f12df017398625ee190c9808f Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Fri, 23 Feb 2018 12:28:43 +0100
Subject: [PATCH] First version of prototype.

---
 gcc.sh         | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/common.opt |  4 ++++
 gcc/gcc.c      | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/gcc.h      |  1 +
 gcc/opts.c     |  3 +++
 gcc/params.c   | 13 +++++++++++++
 gcc/params.h   |  1 +
 7 files changed, 121 insertions(+)
 create mode 100644 gcc.sh

diff --git a/gcc.sh b/gcc.sh
new file mode 100644
index 00000000000..06b16b3152b
--- /dev/null
+++ b/gcc.sh
@@ -0,0 +1,51 @@
+# Please add "source /path/to/bash-autocomplete.sh" to your .bashrc to use this.
+
+log()
+{
+  echo $1 >> /tmp/bash-completion.log
+}
+
+_gcc()
+{
+    local cur prev prev2 words cword argument prefix
+    _init_completion || return
+    _expand || return
+
+    # extract also for situations like: -fsanitize=add
+    if [[ $cword > 2 ]]; then
+      prev2="${COMP_WORDS[$cword - 2]}"
+    fi
+
+    log "cur: '$cur', prev: '$prev': prev2: '$prev2' cword: '$cword'"
+
+    # sample: -fsan
+    if [[ "$cur" == -* ]]; then
+      argument=$cur
+    # sample: -fsanitize=
+    elif [[ "$cur" == "=" && $prev == -* ]]; then
+      argument=$prev$cur
+      prefix=$prev$cur
+    # sample: -fsanitize=add
+    elif [[ "$prev" == "=" && $prev2 == -* ]]; then
+      argument=$prev2$prev$cur
+      prefix=$prev2$prev
+    # sample: --param lto-
+    elif [[ "$prev" == "--param" ]]; then
+      argument="$prev $cur"
+      prefix="$prev "
+    fi
+
+    log  "argument: '$argument', prefix: '$prefix'"
+
+    if [[ "$argument" == "" ]]; then
+      _filedir
+    else
+      # In situation like '-fsanitize=add' $cur is equal to last token.
+      # Thus we need to strip the beginning of suggested option.
+      flags=$( gcc --completion="$argument" 2>/dev/null | sed "s/^$prefix//")
+      log "compgen: $flags"
+      [[ "${flags: -1}" == '=' ]] && compopt -o nospace 2> /dev/null
+      COMPREPLY=( $( compgen -W "$flags" -- "") )
+    fi
+}
+complete -F _gcc gcc
diff --git a/gcc/common.opt b/gcc/common.opt
index d6ef85928f3..389d4fa0385 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -254,6 +254,10 @@ Driver Alias(S)
 -compile
 Driver Alias(c)
 
+-completion=
+Common Driver Joined
+--param Bash completion.
+
 -coverage
 Driver Alias(coverage)
 
diff --git a/gcc/gcc.c b/gcc/gcc.c
index a716f708259..dab88f44d27 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -220,6 +220,8 @@ static int print_help_list;
 
 static int print_version;
 
+static const char *completion = NULL;
+
 /* Flag indicating whether we should ONLY print the command and
    arguments (like verbose_flag) without executing the command.
    Displayed arguments are quoted so that the generated command
@@ -3818,6 +3820,11 @@ driver_handle_option (struct gcc_options *opts,
       add_linker_option ("--version", strlen ("--version"));
       break;
 
+    case OPT__completion_:
+      validated = true;
+      completion = decoded->arg;
+      break;
+
     case OPT__help:
       print_help_list = 1;
 
@@ -7300,6 +7307,12 @@ driver::main (int argc, char **argv)
   maybe_putenv_OFFLOAD_TARGETS ();
   handle_unrecognized_options ();
 
+  if (completion)
+    {
+      suggest_completion (completion);
+      return 0;
+    }
+
   if (!maybe_print_and_exit ())
     return 0;
 
@@ -7868,6 +7881,41 @@ driver::suggest_option (const char *bad_opt)
      (auto_vec <const char *> *) m_option_suggestions);
 }
 
+void
+driver::suggest_completion (const char *starting)
+{
+  /* Lazily populate m_option_suggestions.  */
+  if (!m_option_suggestions)
+    build_option_suggestions ();
+  gcc_assert (m_option_suggestions);
+
+  if (starting[0] == '-')
+    starting++;
+
+  size_t l = strlen (starting);
+  const char *prefix = "-param";
+  if (l >= strlen (prefix) && strstr (starting, prefix) == starting)
+    {
+      /* We support both '-param-xyz=123' and '-param xyz=123' */
+      starting += strlen (prefix);
+      char separator = starting[0];
+      starting++;
+      if (separator != ' ' && separator != '=')
+	return;
+
+      param_print_candidates (separator, starting);
+      return;
+    }
+
+  for (int i = 0; i < m_option_suggestions->length (); i++)
+    {
+      char *candidate = (*m_option_suggestions)[i];
+      if (strlen (candidate) >= l
+	  && strstr (candidate, starting) == candidate)
+	printf ("-%s\n", candidate);
+    }
+}
+
 /* Reject switches that no pass was interested in.  */
 
 void
diff --git a/gcc/gcc.h b/gcc/gcc.h
index ddbf42f78ea..e786e912943 100644
--- a/gcc/gcc.h
+++ b/gcc/gcc.h
@@ -47,6 +47,7 @@ class driver
   void maybe_putenv_OFFLOAD_TARGETS () const;
   void build_option_suggestions (void);
   const char *suggest_option (const char *bad_opt);
+  void suggest_completion (const char *starting);
   void handle_unrecognized_options ();
   int maybe_print_and_exit () const;
   bool prepare_infiles ();
diff --git a/gcc/opts.c b/gcc/opts.c
index 33efcc0d6e7..ed102c05c22 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1982,6 +1982,9 @@ common_handle_option (struct gcc_options *opts,
       opts->x_exit_after_options = true;
       break;
 
+    case OPT__completion_:
+      break;
+
     case OPT_fsanitize_:
       opts->x_flag_sanitize
 	= parse_sanitizer_options (arg, loc, code,
diff --git a/gcc/params.c b/gcc/params.c
index 623296ce49b..6b97e524984 100644
--- a/gcc/params.c
+++ b/gcc/params.c
@@ -179,6 +179,19 @@ param_string_value_p (enum compiler_param index, const char *value_name,
   return true;
 }
 
+void
+param_print_candidates (const char separator, const char *starting)
+{
+  size_t l = strlen (starting);
+  for (unsigned i = 0; i < num_compiler_params; ++i)
+    {
+      const char *candidate = compiler_params[i].option;
+      if (strlen (candidate) >= l
+	  && strstr (candidate, starting) == candidate)
+	printf ("--param%c%s\n", separator, candidate);
+    }
+}
+
 /* Set the VALUE associated with the parameter given by NAME in PARAMS
    and PARAMS_SET.  */
 
diff --git a/gcc/params.h b/gcc/params.h
index 98249d2a1f6..7118fea9f14 100644
--- a/gcc/params.h
+++ b/gcc/params.h
@@ -91,6 +91,7 @@ enum compiler_param
 extern bool find_param (const char *, enum compiler_param *);
 extern const char *find_param_fuzzy (const char *name);
 extern bool param_string_value_p (enum compiler_param, const char *, int *);
+extern void param_print_candidates (const char separator, const char *starting);
 
 /* The value of the parameter given by ENUM.  Not an lvalue.  */
 #define PARAM_VALUE(ENUM) \
-- 
2.16.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]