Skip to content

Run, evaluate and compile functionality for a variety of different languages and modes.

License

Notifications You must be signed in to change notification settings

plandes/flex-compile

Repository files navigation

Flexible Evaluation and Compilation

MELPA badge MELPA stable badge Build Status

Run, evaluate and compile functionality for a variety of different languages and modes. The specific "compilation" method is different across each add-on library, which are called flexible compilers. For example, for ESS and Clojure you can evaluate a specific file and/or evaluate a specfic expression via a REPL. For running a script or starting a make an async process is started.

Table of Contents

Introduction

The general idea is the keybindings to compile you get use to are "switched" to whatever specific problem you're working on. For example, if you're compiling with a makefile, use the make compiler to initiate an make process. If you're working with a REPL based langauage (i.e. flex-compile-python, flex-compile-clojure etc) instead a buffer or expression is evaluated.

Motivation

Many of the "compilers" (i.e. the flex-compile-command and flex-compile-script) don't do much more than invoke a function or execute a script. However, when jumping between several development tasks the strength of the library comes from easily switching between compilers using the same keybindings and finger muscle memory to invoke them.

Configuration

Add the following to your ~/.emacs file:

(require 'flex-compile)
(flex-compile-init)
;; recommended to bind functions globally but not necessary
(flex-compile-key-bindings)

This loads the library and creates global key bindings.

Usage

Most flexible compilers (any subclass of config-flex-compiler) define a specific source file called the config file.

There are the operations (also included are the given key bindings):

  • Choose a Compiler (C-x C-p or M-x flex-compiler-do-activate): select/activate a flex compiler.
  • Set Configuration (C-u C-x C-u or C-u M-x flex-compiler-do-compile): This allows the configuration of the compiler. In most compilers the first step is to select the property, then the configuration for that property is prompted. In some cases a specific property is set, like the Make compiler jumps to the target. All properties are always available for configuration with C-u 0 C-x C-u.
  • Select or Get Information (M-x flex-compiler-do-list): This displays a list of available compilers that are selectable with RET or provide documentation and configuration with ?. In addition, e configures the compiler.
  • Prompt for Config File (C-u 1 C-x C-u or C-u 1 M-x flex-compiler-do-compile): This the file the compiler will use. For example, the Script compiler will run selected script file and display the output on compile. For REPL compilers, like the Python copiler, the starting directory can also be set (see Set Configuration)..
  • Set Config File (C-u 1 C-x C-i or C-u 1 flex-compiler-do-run-or-set-config): This sets the config file to compile, run or interpret. The term config is a nomenclature and examples include Makefile, .clj, .r, .sh files.
  • Go to Config File (C-u C-x C-i or C-u M-x flex-compiler-do-run-or-set-config): This displays the config file/buffer to the current buffer. For some compilers, this also displays the interactive (i.e. REPL) buffer. See the reveal buffer section for more information, and specifically how to force show the buffer.
  • Compile (C-x C-u or M-x flex-compiler-do-compile): This is the default make something command. For make it invokes the first target, for REPL languages like Clojure and ESS it evaluates a .clj or .r file.
  • Run (C-x C-i or M-x flex-compiler-do-run-or-set-config): This starts invokes a run target for make, starts the REPL for REPL type languages.
  • Evaluate (C-x C-o or M-x flex-compiler-do-eval): This invokes the compiler's evaluation functionality. For REPL based languages, this evaluates the current form and stores the result in the kill buffer.
  • Clean (C-x C-y or M-x flex-compiler-do-clean): This invokes the clean target for make and kills the REPL for REPL based compilers.
  • Generate Compiler Docs (M-x flex-compiler-doc-show): this generates the documentation given in the compilers section (verbatim).

Each compiler also has configuration setting ability, which is invoked with the C-u universal argument to the compile C-x C-u invocation per the aforementioned flex-compiler-do-run-or-set-config.

Special Cases

Some compilers are configured differently for the default configuration key binding. For example the make compiler sets the make target defined in the make file, and in this case uses C-u 0 C-u to set configuration properties.

Compiler Configuration

This package uses a configuration system that moves the responsibility out of the specific compilers for configuration. This package extends from the config-manage framework in the buffer manage library by extending and building configuration meta data. For example, the M-x flex-compiler-list lists available compiler with ? providing information and e configuring the compiler.

Revealing The Interactive Buffer

One of the features of the flex compiler library is it provides specific behavior on example where and how to display buffers, which is a compiler configuration. These buffers are usually interactive buffers, i.e. REPL buffers. Any compiler that extends single-buffer-flex-compiler has this capability, which include the following:

The two properties for these compilers include:

  • Buffer New Mode: used when the interactive buffer is created.
  • Buffer Exists Mode: used when the interactive buffer is already exists.

These can be set to the Global settings, which means to take it from the customzied variables flex-compile-single-buffer-display-buffer-new-mode and flex-compile-single-buffer-display-buffer-exists-mode. These variables and the compiler level properties can be set to one of:

  • Switch to Buffer means to first pop then switch to the buffer.
  • Display Buffer means to show the buffer in a different window.
  • Next Frame Otherwise Switch means to use the next frame if there are multiple frames, otherwise pop and switch to the buffer.
  • Next Frame Otherwise Display means to use the next frame if there are multiple frames, otherwise show buffer.
  • Next Frame Skip Switch means to do nothing there are multiple frames, otherwise pop and switch to the buffer.
  • Next Frame Skip Display means to do nothing there are multiple frames, otherwise display the buffer.
  • Never means to never show the buffer.
  • Only If Error means to display the buffer if at least one error was detected such a compilation error with the make compiler. Note: and not all compilers support this option.

The decision of where to show a buffer (or not) happens either when the interative buffer is created or during a compilation. In many cases you might not want to ever show the buffer, so you could set both buffer new and exist properties to never. In this case, you still force the interactive buffer with C-u 2 C-x C-i or C-u 2 M-x flex-compiler-run-or-set-config.

Compilers

Concrete instances of flexible compilers that provide a common interface. Each is an implementation of glue code to the respective compilation method.

Note that all compilers that extend from conf-file-flex-compiler, which include make, script, xml-validate, org-mode, python, clojure, and ess have their start-directory property unset each time the config-file is set.

This documentation was generated with M-x flex-compiler-doc-show.

Choice program

Prompt and more easily invoke choice/action based programs using the Choice Program Emacs library.

Properties:

  • Program: An instance of choice-program.
  • Action: The action to invoke on the program.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.

CLI Python

Provides support for user input for action mnemonics and options using Python programs that use the Zensols action CLI.

This compiler gets the command line metadata as a list of actions and their respective positional and option arguments. It this prompts the user with documentation associated, first the action, then the action's arguments. Finally, it constructs the command line and executes the Python program with the arguments.

Properties:

  • Action: The action to invoke on the program.
  • Config File: The file to use for configuring the compiler.
  • Arguments: The arguments to give to the script.
  • Cache Metadata: Whether or not to cache the Python program's CLI metadata.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.
  • Start Directory: The directory for starting the compilation.

Clojure

This is a REPL based compiler that allows for evaluation Clojure buffers, expressions and starting the REPL using Cider.

The Clojure compiler connects using two Cider modes: the default jack-in mode or connecting to a host and port remotely with cider-connect. You can switch betwee these two methods with the given keybindings:

M-x 1 C-u C-x C-u

See documetation with M-h f flex-compiler-query-eval method for more inforamtion (and current binding).

Todo: support multiple Cider buffers as this implementation currently does not.

Properties:

  • Config File: The file to use for configuring the compiler.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.
  • Connect Mode: Defines how to connect to a Clojure REPL.
  • Repl Port: The port running the REPL; default: 32345
  • Output Clear: Whether or not to clear comint buffer after a compilation.
  • Prompt Kill Repl Buffer: If non-nil then prompt to kill a REPL buffer on clean.
  • Repl Buffer Start Timeout: Number of seconds as an integer to wait to start before giving up (and not displaying).
  • Repl Buffer Start Wait: Number of seconds (as a float) to wait before issuing any first command to the REPL.
  • Start Directory: The directory for starting the compilation.

Comint

Send text to any running comint buffer. This is useful for entering a command in a shell, SQL etc buffer that otherwise requires switching back and forth between buffers, which is a hassle.

Properties:

  • Config File: The file to use for configuring the compiler.
  • Content: The string to insert in the buffer referred by the buffer slot.
  • Buffer: The buffer to insert the content slot.
  • Start Directory: The directory for starting the compilation.

Command

This "compiler" is more of a convenience to invoke an Emacs Lisp function or form. This is handy for functions that you end up invoking over and over with M-x (i.e. cider-test-run-ns-tests). See motivation.

Properties:

  • Sexp: The symbol expression to evaluate.

Do nothing

A no-op compiler for the disabled state.

Emacs speaks statistics

This is a REPL based compiler to evaluate R code with Emacs Speaks Statistics .

Properties:

  • Config File: The file to use for configuring the compiler.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.
  • Output Clear: Whether or not to clear comint buffer after a compilation.
  • Prompt Kill Repl Buffer: If non-nil then prompt to kill a REPL buffer on clean.
  • Repl Buffer Start Timeout: Number of seconds as an integer to wait to start before giving up (and not displaying).
  • Repl Buffer Start Wait: Number of seconds (as a float) to wait before issuing any first command to the REPL.
  • Start Directory: The directory for starting the compilation.

Lisp

This is a REPL based compiler that allows for evaluation Lisp buffers and expressions using slime.

Properties:

  • Config File: The file to use for configuring the compiler.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.
  • Compile On Load: Whether to also compile when loading the source file.
  • Output Clear: Whether or not to clear comint buffer after a compilation.
  • Prompt Kill Repl Buffer: If non-nil then prompt to kill a REPL buffer on clean.
  • Repl Buffer Start Timeout: Number of seconds as an integer to wait to start before giving up (and not displaying).
  • Repl Buffer Start Wait: Number of seconds (as a float) to wait before issuing any first command to the REPL.
  • Start Directory: The directory for starting the compilation.

Make

This compiler invokes make as an asynchronous process in a buffer. The first target, run target, and clean target are invoked respectfully with compile, run and clean Emacs commands (see usage).

This is a special compiler in it's configuration. Instead of setting properties, the default configuration mechanism is to set the make target instead. If you want to set a flex compiler property, use \C-u 0 \C-u.

When setting the configuration file the target property is unset.

Properties:

  • Config File: The file to use for configuring the compiler.
  • Target: The make file target to satisfy.
  • Run Target: The target used to run or test as the secondary compilation functionality.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.
  • Start Directory: The directory for starting the compilation.

Org mode

This compiler exports Org mode to external formats and then shows the output in the browser. Only HTML is currently supported.

Properties:

  • Config File: The file to use for configuring the compiler.
  • Export Fn: The Org mode export function.
  • Open File: Whether to open the file after exported.
  • Output Directory: The output directory.
  • Frame Focus Command: The command to refocus the Emacs frame after rendering the output (browser).
  • Frame Focus Delay: Seconds before refocusing the Emacs frame after redering the output.
  • Start Directory: The directory for starting the compilation.

Python

This is a REPL based compiler that allows for evaluation Python buffers and expressions using python mode.

Properties:

  • Config File: The file to use for configuring the compiler.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.
  • Output Clear: Whether or not to clear comint buffer after a compilation.
  • Prompt Kill Repl Buffer: If non-nil then prompt to kill a REPL buffer on clean.
  • Repl Buffer Start Timeout: Number of seconds as an integer to wait to start before giving up (and not displaying).
  • Repl Buffer Start Wait: Number of seconds (as a float) to wait before issuing any first command to the REPL.
  • Start Directory: The directory for starting the compilation.

Script

This compiler runs a script with optional arguments in an async buffer. See motivation.

Properties:

  • Config File: The file to use for configuring the compiler.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.
  • Arguments: The arguments to give to the script.
  • Start Directory: The directory for starting the compilation.

XML

Implementation compiler for XML validation using command line xmllint command line tool.

Properties:

  • Config File: The file to use for configuring the compiler.
  • Schema File: Location of the schema file to validate against.
  • Buffer Exists Mode: Compiler instance of flex-compile-single-buffer-display-buffer-exists-mode.
  • Buffer New Mode: Compiler instance of flex-compile-single-buffer-display-buffer-new-mode.
  • Kill Buffer Clean: If non-nil kill the buffer on clean.
  • Start Directory: The directory for starting the compilation.

Invoking a Compiler Programmatically

There might be instances where it's necessary to execute other actions along with a compilation. If you know Emacs Lisp, you can create your own function to invoke other compilers, and then use the Command compiler to invoke it as a command (an interactive function), such as:

(defun clean-and-call-python-compiler ()
  "Invoke `make clean', then call the Python compiler."
  (interactive)
  (shell-command "make clean")
  (let ((this (flex-compiler-by-name "python")))
    (flex-compiler-compile this)))

Other Emacs Lisp snippets that do things with compilers:

;; names of compilers
(let* ((this flex-compile-manage-inst)
       (names (config-manager-entry-names this)))
  names)

;; the currently set compiler's name and descriptor
(let* ((this flex-compile-manage-inst)
       (active (flex-compile-manager-active this)))
  (format "Current compiler: %s (desc: %s)"
      (slot-value active 'object-name)
      (slot-value active 'description)))

;; get a compiler by name and set its configuration file
(let ((this (flex-compiler-by-name "python")))
  (with-slots (config-file start-directory) this
    (setq config-file "~/work/src/example.py"
          start-directory "~/work")))

;; run the compiler
(let ((this (flex-compiler-by-name "python")))
  (flex-compiler-compile this))

;; set the active compilerby name
(let ((this flex-compile-manage-inst))
  (config-manager-activate this "python"))

Writing Your Own Compiler

Writing your own flexible compiler is pretty easy if you know how to write Emacs object oriented programs. Even if you don't, you should be able to find a compiler already written that follows your use case among those concerete (see compilers) that are already given in this package. You can also submit an issue (see the contributing instructions).

Changelog

An extensive changelog is available here.

License

Copyright © 2017-2023 Paul Landes

GNU Lesser General Public License, Version 2.0