morpher

Run code transformations on the current buffer

suchipi

60

1

1.1.1

MIT

GitHub

morpher

morpher is a package for the atom text editor that provides an API and UI for programmatically changing the text, cursor position, and selection range of the current buffer.

The user writes "transforms" in ~/.atom/morpher-transforms.js, and can bring up a list of these transforms, then choose one to execute on the current buffer.

Usage example gif

Transform functions receive:

And can modify:

Documentation

All transforms are defined in ~/.atom/morpher-transforms.js, known as "the transforms file". Each time the command "Morpher: Open Transform List" is run (from the command palette or via keystroke), morpher loads all the transforms exported from this file and presents them in a list to the user.

Morpher will reload the transforms file each time you open the list.

The transforms file should export a function that returns either an Array of transforms or a Promise that resolves to an Array of transforms.

A transform is an object with these properties:

The onSelected function will be called with an object called the "buffer state". The buffer state represents the current state of the active buffer in the editor. It has these properties:

The return value of the onSelected function is an object describing the changes that should be applied to the buffer, called a "transform result". onSelected can return a transform result or a Promise that resolves to one. A transform result has these properties:

You may notice that a transform result is shaped almost the same as a buffer state, but does not include filePath.

Here are some flowtype definitions for the concepts:

type BufferState = {
  text: string,
  selectedText: string,
  cursorPosition: Point,
  selection: Range,
  filePath?: string,
  variables?: {[variable: string]: string},
};

type TransformResult = {
  text?: string,
  selectedText?: string,
  cursorPosition?: Point | [number,  number],
  selection?: Range | [[number, number], [number, number]],
};

type VariablesConfig = {
  [variable: string]: {
    label?: string, // (default: variable)
    multiline?: boolean, // (default: false)
    defaultValue?: string, // (default: empty string)
  },
};

type Transform = {
  name: string,
  description?: string,
  onSelected: (BufferState) => TransformResult | void | Promise<TransformResult | void>,
  variables?: VariablesConfig | (BufferState) => (VariablesConfig | Promise<VariablesConfig>),
};

type TransformsFileExport = () => Array<Transform> | Promise<Array<Transform>>,

Here's some example transforms:

const { TextBuffer, Point } = require("atom");

module.exports = function() {
  return [
    {
      name: "Uppercase selected text",
      description: "Converts all characters in the selection to uppercase",
      onSelected({ selectedText }) {
        return { selectedText: selectedText.toUpperCase() };
      },
    },
    {
      name: "Move cursor to start",
      onSelected() {
        return {
          cursorPosition: new Point(0, 0)
        };
      },
    },
    {
      name: "Add // @flow",
      description: "Adds '// @flow' to the top of the file (if not present)",
      onSelected({ text }) {
        if (text.split("\n")[0].indexOf("// @flow") === -1) {
          return { text: "// @flow\n" + text };
        }

        // If you don't return anything, nothing will happen
      }
    },
  ];
};