sirrobert-string-completion

A string-completion module.

Usage no npm install needed!

<script type="module">
  import sirrobertStringCompletion from 'https://cdn.skypack.dev/sirrobert-string-completion';
</script>

README

Rationale

A module for string completion. Historically, this came out of a linux-based javascript shell I wrote (sirrobert-shell). I modularized the tab completion as this for re-use in some other stuff as well.

Namespace rationale

This module exists in the sirrobert- namespace so as not to clutter npm and to keep my related packages together. If there's interest, I can move this into the general namespace.

Installation

Local installation

npm install --save sirrobert-string-completion

Global installation

npm install --global sirrobert-string-completion

The Completion Object

Two things are needed to do string completion with this module:

  • A string to be completed.
  • a function that returns an array of completion options

Using these two, a string can be completed according to the provided function (the completion method). Here's the basic gist:

  1. Craete your completion object
  2. Call the expansion method
  3. Get the expanded string

The most simple version of that would look like this:

let Tab = require("sirrobert-string-completion");
let input = "squirrel";
let method = function () { return ["A","B","C"] };
let expanded = new Tab().expand(method).expandLine(input); // "squirrelA"

Constructor Options (and Object Properties)

In addition to an ad-hoc approach, you can also use a parameterized form for better control. Using this approach offers more functionality.

The following is an example construction that uses all of the available options.

var tab = new Completion({
  input   : "profile_p",    // A filename to expand to "profile_pic.jpg"
  cursor : 0,              // Match from the end of the input
  number : 2,              // Select the second match found
  method : myfunc,         // A function that returns an array of matches
  mode   : "replace-word", // The default.  Replace the rest of the word
  data   : "./myDir/foo",  // the directory to scan
});

These options correspond directly to object properties. Here are the objects with their default values.

tab.input    // ""
tab.cursor  // 0
tab.number  // 0
tab.method  // null
tab.mode    // "replace-word"
tab.data    // null

An additional property is available but is not settable as an option:

tab.result  // new CompletionResult({tab:this});

A detailed description of each is below.

  • input The input string to be expanded.

  • cursor The location within the input at which expansion should happen. For example, with a string of "squirrel", a cursor of 0 would mean that the expansion should be based on "squirre" with the "l" appended to the result. You can think of "cursor" as "how many letters are after the expansion point."

  • number The ordinal number (starting with 1) of the result that should be used. For example, if you are expanding a file name with the input input "st" and the available matches include ["stop.jpg","strong.jpg","store.jpg"], a number of 1 would expand to "stop.jpg". A number of 2 expands to "strong.jpg", a number of 3 expands to "store.jpg". Numbers below 1 are floored at 1. Numbers above the number of matches are looped, so a number of 4 expansd to "stop.jpg" again.

    Note that changing the number does not affect the order of the matches (as stored in the .matches property). Instead, an offset copy of the matches is stored in the property .offsetMatches. String completion is based off the .offsetMatches array.

  • mode The completion mode. Defaults to replace-word.

    • replace-word Default. Replaces the rest of the current string. If the cursor is in the middle of a word, the remainder of the word is replaced.

    • infix Inserts the desired match at the cursor.

    • suffix Appends the desired match to the end of the input string. This is differs from { cursor: 0 } in that this option simply appends, rather than attempting to merge the match at the end.

  • method The function used to generate string completion matches. The function takes two arguments:

    • object Object refers to the Completion object, itself.

    • data Data is anything relevant to the expansion. It is passed in as an argument to the .match() method. For example, if you are trying to complete a file name in the current directory, you may want to pass the current directory in as data.

  • data Arbitrary data to pass into the method. Note that this cannot be a function. If you need to pass a function, consider wrapping it in an array: data: [function () { ... }]

Methods

The Completion object has only one method: .match()

  • .match(method)
  • .match(data)
  • .match(method,data)

Arguments: method, match

Both arguments are optional.

  • method is the method for finding matches. See the construction options above for a complete description.

  • data is optional data to pass into the method. See the construction options above for a complete description.

The CompletionResult Object

When using the Completion object, the object has a .result property. This property is a CompletionResult object. The object has three properties and two methods.

Properties

  • .matches An array of matches as returned by the expansion method.
  • .offsetMatches The matches array shifted cyclicly by the .selectNumber() method. See the method description for more information.
  • .tab A reference to the completion object of which this is a result.

Methods

selectNumber(number)

Create a copy of the .matches property as the .offsetMatches property. Then cycle the array enough times that the numberth item is first. Here's a practical example.

tab.result.matches;           // ["a", "b", "c", "d", "e"]
tab.result.selectNumber(3);   // ["c", "d", "e", "a", "b"]

Notice that the 3rd match is now the first offsetMatch. Notice also that "a" and "b" that were shifted off the front of the array were pushed to the end of the array. In this way, if you selected more items than the length of the array, you just loop back on yourself. Another example:

tab.result.matches;            // ["a", "b", "c", "d", "e"]
tab.result.selectNumber(32);   // ["b", "c", "d", "e", "a"]

By selecting the 32nd result on an array with 5 elements, we end up at the second element.

This was originally introduced for the sirrobert-shell module that had command-input tab completion. This allowed for things like cycling through options when the user pressed tab multiple times.

expand([input],[options])

  • .expand()
  • .expand(input)
  • .expand(input, options)

Returns a new string with the expansion made.

Expands a string of text according to the options. If input is omitted, the Completion object's input property is used. If options are omitted, the Completion object's various properties are used (as set during construction). See the Completion object's description for more details.

Usage

I use this module for tab completion in a shell. That's why I use the variable name tab. Here are some examples.

let Completion = require("squirrel-string-completion");

var tab = new Completion({
  input: "sto",
  cursor: 0,
  number: 1,
  method: function (obj, opt) {
    return ["stop.jpg", "stock.jpg", "store.jpg"];
  },
});

tab.expand().result.expandLine();                   // stop.jpg
tab.result.expandLine({result: 2});                 // stock.jpg
tab.result.expandLine({result: 3});                 // store.jpg
tab.result.expandLine({result: 3, mode: "suffix"}); // stostore.jpg

LICENSE

MIT