Detect infinite loops in alias expansion

This commit is contained in:
Isaac Khor 2018-01-09 17:34:15 +08:00
parent 1203dbd86b
commit 36bea9718a
No known key found for this signature in database
GPG key ID: D05A4A7EC9BCB5A9
2 changed files with 30 additions and 3 deletions

View file

@ -26,13 +26,23 @@ export function expandExstr(exstr: string): string {
*
* @param command The command portion of the exstr
*/
export function getAliasExpandRecur(command: string): string {
export function getAliasExpandRecur(
command: string, prevExpansions: string[] = []): string {
// Base case: alias not found; return original command
if(!commandIsAlias(command)) {
return command
}
// Infinite loop detected
if(prevExpansions.includes(command)) {
throw `Infinite loop detected while expanding aliases. Stack: ${prevExpansions}.`
}
// Add command to expansions used so far
prevExpansions.push(command)
// Alias exists; expand it recursively
const expanded = Config.get("exaliases", command)
return getAliasExpandRecur(expanded)
return getAliasExpandRecur(expanded, prevExpansions)
}

View file

@ -98,6 +98,7 @@ import * as config from './config'
import * as Logging from "./logging"
const logger = new Logging.Logger('excmds')
import * as aliases from './aliases'
/** @hidden */
//#background_helper
@ -1079,7 +1080,8 @@ export async function buffer(index: number | '#') {
// {{{ SETTINGS
/** Similar to vim's `:command`. Maps one ex-mode command to another.
/**
* Similar to vim's `:command`. Maps one ex-mode command to another.
* If command already exists, this will override it, and any new commands
* added in a future release will be SILENTLY overridden. Aliases are
* expanded recursively.
@ -1091,11 +1093,23 @@ export async function buffer(index: number | '#') {
*
* Note that this is only for excmd->excmd mappings. To map a normal-mode
* command to an excommand, see [[bind]].
*
* See also:
* - [[comclear]]
*/
//#background
export function command(name: string, ...definition: string[]) {
const def = definition.join(" ")
config.set("exaliases", def, name)
// Warn user about infinite loops
try {
aliases.getAliasExpandRecur(name)
} catch(e) {
fillcmdline_notrail(e, ' Alias unset.')
config.unset("exaliases", def)
return
}
}
/**
@ -1104,6 +1118,9 @@ export function command(name: string, ...definition: string[]) {
*
* For example: `comclear helloworld` will reverse any changes caused
* by `command helloworld xxx`
*
* See also:
* - [[command]]
*/
//#background
export function comclear(name: string) {