Permalink
Commits on Aug 11, 2017
  1. Configure completions for common commands.

    georgebrock committed Jul 12, 2017
    This tab completion configuration file includes:
    
    - All Git commands without arguments.
    - Popular Git commands, with their options and arguments.
    - Internal gitsh commands, with their options and arguments.
    
    There are some argument types that we can't currently complete, and others
    that are unlikely to ever be practical to complete. To represent those this
    commit also introduces a `$anything` variable to the tab completion DSL. The
    variable's corresponding `AnythingMatcher` class will match any input, but
    produce no completions.
    
    The options and arguments supported in the file are based on the manual
    pages from Git 2.13.3. Other versions of Git support slightly different
    options and arguments, which means we might complete things that don't work.
  2. Completion DSL: Support multiple option arguments.

    georgebrock committed Jul 14, 2017
    For example, git-config(1) has a few options that take two arguments:
    
        config $opt*
          --get-color $anything $anything?
          --get-colorbool $anything (true|false)?
  3. Completion DSL: Allow leading/trailing blank lines.

    georgebrock committed Jul 13, 2017
    This commit adds support for leading and trailing blank lines to the tab
    completion DSL.
Commits on Jul 12, 2017
  1. Add option support to the tab completion DSL.

    georgebrock committed Jul 3, 2017
    This commit expands the tab completion DSL with the ability to define
    options like `-f` or `--force`.
    
    Rules can contain an `$opt` variable, which indicates where options may
    appear. This will match on anything beginning with `-` or `--`, and
    complete to any known options.
    
    The known options are listed as indented lines after the first line of the
    rule, with any arguments the options take specified in the same way as
    the command's arguments would be.
    
    For example:
    
    ```
    commit $opt* --? $path+
      --all
      --fixup $revision
      --file $path
      --untracked-files (no|normal|all)?
    ```
Commits on Jul 3, 2017
  1. Add * and ? operators to git_completions(5)

    georgebrock committed Jul 3, 2017
    This commit adds support for the * operator (zero or more times), and the ?
    operator (zero or one times) to the gitsh tab completion DSL.
  2. Filter out duplicate completions.

    georgebrock committed Jul 3, 2017
    Our ability to detect incomplete paths is based on there being a single
    result (e.g. if you complete "s" to "src/" we don't want to append a space
    as we normally would when there's a single completion).
    
    Now that the completion system uses an NFA, it's possible to get duplicate
    values (e.g. a command like `add $path* --? $path+` would invoke the `$path`
    matcher twice in some situations).
    
    This commit makes sure we filter out the duplicates so that the incomplete
    path detection continues to work.
    
    (While we're modifying the only line in this method, also move it to get
    dependency order between #matches and #completions)
  3. DSL to define tab completion automaton state graph

    georgebrock committed Jun 29, 2017
    This commit introduces a domain specific language (DSL) to define the state
    graph for the tab completion automaton. It also replaces the hard-coded
    state graph with an equivalent graph loaded from a configuration file.
    
    The details of the DSL are given in the gitsh_completions(5) manual page
    which is added in this commit.
    
    The DSL will need to be expanded somewhat to do everything we want the tab
    completion system to be able to do, but this is a good step in that
    direction.
  4. Update hound config.

    georgebrock committed Jun 30, 2017
    This commit makes the Rubocop config used by Hound more consistent with the
    existing project style.
Commits on Jun 25, 2017
  1. Tab completion NFA state graph visualization tool.

    georgebrock committed Jun 23, 2017
    The tab completion system that was introduced in 1b673e5 uses a
    Non-deterministic Finite Automaton (NFA) to understand the user's input and
    select relevant completions. The NFA has a directed graph of states.
    
    While the current NFA's state graph is small, the intention is to replace it
    with a much larger and more complex graph.
    
    This commit introduces a visualization tool, which outputs a representation
    of the NFA's state graph in Graphviz's dot language.
Commits on Jun 20, 2017
  1. Support tab completion for variables.

    georgebrock committed Apr 30, 2017
    This commit introduces a `Gitsh::TabCompletion::VariableCompleter` object.
    This is completely separate from the NFA-based completion we use for most
    things, because:
    
    - we immediately know we need to use variable completion based on lexical
      analysis of the input without having to walk through the NFA's states,
      and
    
    - the context in which the variable appears doesn't inform the completions
      we present the user with.
    
    The `Gitsh::TabCompletion::Facade` object gains the responsibility of
    deciding which type of completion to invoke, based on information from the
    `Gitsh::TabCompletion::Context` object.
    
    To load the config variables, we try to use the `git status --list
    --name-only` command. However, this command was only introduced in Git 2.6,
    and versions back to 2.4 are still officially supported by the Git team. If
    running the command with `--name-only` fails we fall back to parsing the
    output of `git status --list`.
    
    We don't use the backward compatible version everywhere, because the parsing
    won't be perfect for multi-line config values (`--name-only` was introduced
    to address this problem).
Commits on Jun 16, 2017
  1. Improve variable lexing.

    georgebrock committed Jun 16, 2017
    Prior to this commit, an incomplete variable reference (a line ending with
    an unescaped `$` character, or unclosed `${`) would produce a lexing error.
    After this commit it produces a parse error instead.
    
    We want to start using the lexer for understanding tab completion context,
    which means we need to lex incomplete input. Having all legal-but-incomplete
    input cause parse errors instead of lexing errors will make this much
    easier.
    
    Note that it's still possible to produce lexing errors with invalid input,
    but it's more reasonable for the tab completion system to just ignore that
    and not provide any completions.
    
    Previously the token `MISSING` was used to indicate that a line was
    incomplete, but could potentially be made valid with another line of input.
    This commit renames that token to `INCOMPLETE`, and re-purposes `MISSING` to
    mean that something was missing from the end of the line that cannot be
    supplied by an additional line of input.
Commits on Jun 15, 2017
  1. Add CODE_OF_CONDUCT.md

    georgebrock committed Jun 15, 2017
    GitHub has a new feature that indicates if a project has a code of conduct.
    We already had one, linked from `CONTRIBUTING.md`. This commit just
    duplicates that link in a place where GitHub can find it.
Commits on May 25, 2017
  1. Bump version: 0.12

    georgebrock committed May 25, 2017
Commits on May 13, 2017
  1. Support for multi-line commands.

    georgebrock committed Jan 8, 2017
    Line breaks are supported in similar places to sh(1). Line breaks can be
    escaped anywhere by ending a line with a `\` character. Unescaped line
    breaks are also supported:
    
    - after logical operators (`&&` and `||`),
    - within strings,
    - between commands wrapped in parentheses, and
    - between commands in subshells.
    
    The Lexer has been expanded to insert a `MISSING` token in all situations
    where the input is known to be incomplete (i.e. when the input ends with an
    escape character, or the input ends in any of the places where an unescaped
    line break can be used).
    
    After invoking the `Lexer`, the `Interpreter` checks the token stream for
    `MISSING` tokens. If it finds any it requests another line of input from the
    current input strategy, appends it to the current input, and tries again.
    
    A new `EOL` token has been introduced to represent line breaks between
    commands. In the `Parser` it's treated exactly like the `SEMICOLON` token.
    
    Lexical analysis of comments needed to be improved to allow for comments at
    the end of lines in a multi-line command. For example, the following input
    is valid:
    
        (:echo 1 # comment
        :echo 2)
    
    It is semantically equivalent to:
    
        (:echo 1; :echo 2)
    
    To support this, the Lexer will now:
    
    - ignore whitespace before a comment's initial `#` character. This prevents
      extraneous `SPACE` tokens from being produced. A trailing `SPACE` token
      in a single line command is fine, but it can cause problems in a
      multi-line command.
    
    - pop the `:comment` state without consuming the newline character at the
      end of a comment, allowing the default parsing rules to handle the
      newline, and produce an `EOL` token.
Commits on May 6, 2017
  1. Change to the root path with :cd

    georgebrock committed Apr 8, 2017
    `:cd` without an argument will change to the repository's root path
    (`$_root`), much like a general purpose shell's `cd` without an argument
    will change to the user's home directory (`$HOME`).
  2. Introduce a $_root magic variable.

    georgebrock committed Apr 8, 2017
    $_root evaluates to the root directory of the current Git repository.
Commits on Apr 30, 2017
  1. Non-zero exit status for bad scripts.

    georgebrock committed Jan 29, 2017
    When gitsh is invoked in a non-interactive manner, a parse error should
    result in a non-zero exit status.
    
    To make sure this happens, parse error handling has been delegated to the
    input strategies by the interpreter. In an interactive session, we output an
    error message and continue the session. In a non-interactive session, we
    raise a Gitsh::ParseError, which will bubble up to the gitsh binary and
    terminate the session with an exit status of 1.
    
    Since the input strategy for files is used in a few internal places (in the
    interactive input strategy, for loading .gitshrc, and in the :source
    command), those call sites have been modified to handle the possibility of a
    Gitsh::ParseError.
Commits on Apr 25, 2017
Commits on Apr 22, 2017
  1. Remove unused InputStrategies::String class.

    georgebrock committed Apr 22, 2017
    This has been unused since 570c6f9, and should have been removed then.
Commits on Apr 19, 2017
  1. Subshells wrap commands, not strings.

    georgebrock committed Mar 4, 2017
    Instead of storing the command contained by a subshell as a string and
    parsing it separately at execution time, we now parse subshells in the same
    parsing pass that handles the command that contains them, and store a
    Gitsh::Commands::* object.
    
    This has a few advantages:
    
    - A parse error in a subshell is discovered at parse time, not execution
      time.
    - A subshell containing closing parens that do no end the subshell (e.g.
      `:echo $(:echo ")))")` no longer confuses the lexer.
    - We can drop the Gitsh::StringRunner class.
  2. Pass environment to commands at execution time.

    georgebrock committed Mar 4, 2017
    This means we don't have to know what environment a command will be executed
    in when we construct it.
    
    The motivation was simplifying subshell parsing: we'll be able to parse a
    command fully, including the contents of any subshells, in a single pass.
    Previously we couldn't do this because the subshell's environment can't be
    created until the command containing the subshell is executed. Look out for
    this change in a subsequent commit.
    
    A nice side effect of the change was simplifying the Gitsh::Parser: it no
    longer needs a reference to a Gitsh::Environment.
  3. Support parentheses for grouping commands.

    georgebrock committed Jan 29, 2017
    This allows a user to override the default operator precedence, e.g. with
    `(foo || bar) && baz`.
    
    This has the side effect that literal parentheses in unquoted arguments must
    be escaped.
  4. Replace Parslet PEG with RLTK CFG.

    georgebrock committed Dec 26, 2016
    This is a really major change, and therefore a big diff.
    
    Replaces the Parslet-based parsing expression grammar (PEG) with an
    RLTK-based context-free grammar (CFG).
    
    The `Gitsh::Parser` (which converted text into a AST) and
    `Gitsh::Transformer` (which converted the AST into useful domain objects)
    have been replaced with a `Gitsh::Lexer` (which converts text into tokens)
    and `Gitsh::Parser` (which converts tokens into useful domain objects).
    
    Why?
    ====
    
    Distinguishing between _invalid input_ and _valid but incomplete input_ is
    really hard with a PEG. There are various papers on improving PEG error
    reporting, and some support in Parslet for various strategies, but I
    couldn't find a satisfactory way to accurately work out why parsing failed
    without making the grammar significantly more complex.
    
    We want to add support for various multi-line constructs, which means we
    need to know if a line is invalid or just waiting for more input. The
    specific issues I have in mind are:
    
    - Support multi-line strings
      (#31)
    
    - Add a `:function` command for defining functions
      (#35)
    
    We also want to improve tab-completion in various ways, which also involves
    working with very similar types of incomplete input. Most of the
    enhancements we have in mind will only be possible if we know more exactly
    what we're completing, and re-using some of the parsing code to understand
    the input seemed like the most logical approach. Specific issues are:
    
    - Support the same tab completion options as zsh
      (#25)
    
    - Add tab completion for options
      (#80)
    
    - Auto complete stash commands
      (#220)
    
    - Tab completion only works for the first command on the line
      (#261)
    
    Note that this commit doesn't implement any of these enhancements, it just
    makes them more likely to happen in the future.
    
    Implementation details
    ======================
    
    - Introduces equality methods on argument objects, used to testing parser
      output.
    
    - git-prefix correction (i.e. interpreting `git foo` as `foo` when
      `help.autocorrect` is set) has moved from the Parser to the GitCommand
      class.
    
    - The subshell implementation in this commit is not very good. It will be
      significantly improved in the next couple of commits, but it seemed too
      big of a change to roll into this one.
  5. Bump version: 0.11.2

    georgebrock committed Apr 19, 2017
Commits on Apr 14, 2017
  1. Improve configure script's source file discovery.

    georgebrock committed Apr 3, 2017
    - Uses Autoconf's `$srcdir` instead of `basename $0` as the root of the
      source tree.
    
    - Removes a redundant `cut`. This was intended to strip `./` from the
      beginnings of the resulting paths, but it wasn't portable (`./` wasn't
      prepended to the paths on some systems), and the way this list is
      generated and used has changed so much that it no longer appears to matter
      if the `./` is there at all.
    
    Partly based on Mike Burns' patch to `configure` in the OpenBSD ports tree:
      https://marc.info/?l=openbsd-ports&m=148340820830595&w=2
Commits on Apr 8, 2017
  1. Support explicit architectures for Readline.

    georgebrock committed Apr 8, 2017
    On macOS systems, universal binaries contain multiple architectures, e.g.
    the system Ruby is built for both i386 and x86_64. The Ruby `mkmf.rb` build
    system will default to building universal C extensions when used with a
    universal Ruby.
    
    When installing gitsh via Homebrew, we build against the Homebrew version of
    Readline. Until recently, this was a universal library (x86_64 & i386) but
    is now x86_64 only [1].
    
    It is possible to build against a universal Ruby and a non-universal
    Readline, but only if the right flags are passed to the C extension's
    `extconf.rb` script.
    
    This commit:
    
    - Adds support for a `$READLINE_ARCH` environment variable. When it is set,
      the `configure` script will pass the right `--with-arch-flags` argument to
      `extconf.rb`.
    
    - Updates the Homebrew formula to set `$READLINE_ARCH` based on the host
      OS's preferred architecture.
    
    [1]: Homebrew/homebrew-core#10907
  2. Support ruby22, ruby23, ruby24 binaries.

    georgebrock committed Apr 8, 2017
    Some systems, e.g. OpenBSD, include the version number in the name of the
    Ruby binary. We support all of these versions, so we should support all of
    these names.
  3. Support alternative names for Readline.

    georgebrock committed Apr 3, 2017
    The OpenBSD port for Readline calls the library `ereadline`, which means
    that the gitsh configure script needed to be patched to be used on
    OpenBSD systems.
    
    This commit introduces a `READLINE_LIB` environment variable, which can be
    used to specify an alternative name to be passed to the Ruby C-extension's
    configuration script.
    
    Based on Mike Burns' patch to `configure` in the OpenBSD ports tree:
      https://marc.info/?l=openbsd-ports&m=148340820830595&w=2
Commits on Apr 3, 2017
  1. Upgrade test dependencies.

    georgebrock committed Apr 3, 2017
    Gets rid of a bunch of deprecation warnings when running the test suite
    under Ruby 2.4.
  2. Update CI Ruby versions.

    georgebrock committed Apr 3, 2017
    - Add 2.4.
    - Update older versions to their newest patch level.
Commits on Jan 6, 2017
  1. Refactor from runners to input strategies.

    georgebrock committed Jan 6, 2017
    This commit replaces the `Gitsh::InteractiveRunner` and
    `Gitsh::ScriptRunner` classes with input strategies
    (`Gitsh::InputStrategies::Interactive` and `Gitsh::InputStrategies::File`).
    Previously each runner class's `#run` method would loop over available input
    and pass each command to the interpreter. Now the interpreter controls the
    loop and asks the strategy for commands.
    
    The main motivation is to support multi-line constructs. We would've needed
    to add very similar code for handling incomplete input to both the runner
    classes. Now that the interpreter is responsible for controlling to overall
    flow of the session, we'll be able to handle incomplete input in one place.
    
    A nice side-effect is that the `Gitsh::CLI` code is cleaner, and now uses
    conditionals to create different strategies instead of using conditionals to
    fork the control flow.
    
    This commit also introduces some new `Gitsh::*Runner` classes, which take
    over responsibility for the places where we still need to execute some gitsh
    code outside of the main run loop:
    
    * The old `Gitsh::ScriptRunner` class was used to load the `.gitshrc` file
      at the start of an interactive session, and by the internal `:source`
      command.  This has been replaced with a `Gitsh::FileRunner` that handles
      setting up a `Gitsh::InputStrategies::File` and a `Gitsh::Interpreter` for
      a given file.
    
    * Similarly, the old `Gitsh::Interpreter#execute` method was used by
      `Gitsh::Arguments::Subshell` to run the contents of a subshell. This has
      been replaced with a `Gitsh::StringRunner` and associated
      `Gitsh::InputStrategies::String`.
  2. Homebrew: use env=std by default.

    georgebrock committed Dec 23, 2016
    This causes Homebrew to set the appropriate LDFLAGS for Readline, which
    is a keg only formula.
    
    Without this, gitsh can't build against system Ruby (although it still
    worked on systems where Homebrew's ruby formula was installed).
    
    I couldn't find good documentation for the difference between `env=std`
    and `env=superenv`, but this is where the necessary LDFLAGS value is set:
    
      https://github.com/Homebrew/brew/blob/89fd34b/Library/Homebrew/build.rb#L100