package edit

import (
	
	
	

	
	
	
	
	
	
	
)

//elvdoc:var max-height
//
// Maximum height the editor is allowed to use, defaults to `+Inf`.
//
// By default, the height of the editor is only restricted by the terminal
// height. Some modes like location mode can use a lot of lines; as a result,
// it can often occupy the entire terminal, and push up your scrollback buffer.
// Change this variable to a finite number to restrict the height of the editor.

func ( *cli.AppSpec,  eval.NsBuilder) {
	 := newIntVar(-1)
	.MaxHeight = func() int { return .GetRaw().(int) }
	.Add("max-height", )
}

func ( *cli.AppSpec,  *eval.Evaler,  eval.NsBuilder) {
	initBeforeReadline(, , )
	initAfterReadline(, , )
}

//elvdoc:var before-readline
//
// A list of functions to call before each readline cycle. Each function is
// called without any arguments.

func ( *cli.AppSpec,  *eval.Evaler,  eval.NsBuilder) {
	 := newListVar(vals.EmptyList)
	["before-readline"] = 
	.BeforeReadline = append(.BeforeReadline, func() {
		callHooks(, "$<edit>:before-readline", .Get().(vals.List))
	})
}

//elvdoc:var after-readline
//
// A list of functions to call after each readline cycle. Each function is
// called with a single string argument containing the code that has been read.

func ( *cli.AppSpec,  *eval.Evaler,  eval.NsBuilder) {
	 := newListVar(vals.EmptyList)
	["after-readline"] = 
	.AfterReadline = append(.AfterReadline, func( string) {
		callHooks(, "$<edit>:after-readline", .Get().(vals.List), )
	})
}

//elvdoc:var add-cmd-filters
//
// List of filters to run before adding a command to history.
//
// A filter is a function that takes a command as argument and outputs
// a boolean value. If any of the filters outputs `$false`, the
// command is not saved to history, and the rest of the filters are
// not run. The default value of this list contains a filter which
// ignores command starts with space.

func ( *cli.AppSpec,  *eval.Evaler,  eval.NsBuilder,  histutil.Store) {
	 := eval.NewGoFn("<ignore-cmd-with-leading-space>",
		func( string) bool { return !strings.HasPrefix(, " ") })
	 := newListVar(vals.MakeList())
	["add-cmd-filters"] = 

	.AfterReadline = append(.AfterReadline, func( string) {
		if  != "" &&
			callFilters(, "$<edit>:add-cmd-filters",
				.Get().(vals.List), ) {
			.AddCmd(store.Cmd{Text: , Seq: -1})
		}
		// TODO(xiaq): Handle the error.
	})
}

//elvdoc:var global-binding
//
// Global keybindings, consulted for keys not handled by mode-specific bindings.
//
// See [Keybindings](#keybindings).

func ( *cli.AppSpec,  notifier,  *eval.Evaler,  eval.NsBuilder) {
	 := newBindingVar(emptyBindingsMap)
	.GlobalBindings = newMapBindings(, , )
	.Add("global-binding", )
}

func ( *eval.Evaler,  string,  vals.List,  ...interface{}) {
	if .Len() == 0 {
		return
	}

	,  := eval.PortsFromStdFiles(.ValuePrefix())
	 := eval.EvalCfg{Ports: [:]}
	defer ()

	 := -1
	for  := .Iterator(); .HasElem(); .Next() {
		++
		 := fmt.Sprintf("%s[%d]", , )
		,  := .Elem().(eval.Callable)
		if ! {
			// TODO(xiaq): This is not testable as it depends on stderr.
			// Make it testable.
			diag.Complainf(os.Stderr, "%s not function", )
			continue
		}

		 := .Call(, eval.CallCfg{Args: , From: }, )
		if  != nil {
			diag.ShowError(os.Stderr, )
		}
	}
}

func ( *eval.Evaler,  string,  vals.List,  ...interface{}) bool {
	if .Len() == 0 {
		return true
	}

	 := -1
	for  := .Iterator(); .HasElem(); .Next() {
		++
		 := fmt.Sprintf("%s[%d]", , )
		,  := .Elem().(eval.Callable)
		if ! {
			// TODO(xiaq): This is not testable as it depends on stderr.
			// Make it testable.
			diag.Complainf(os.Stderr, "%s not function", )
			continue
		}

		, ,  := eval.CapturePort()
		if  != nil {
			diag.Complainf(os.Stderr, "cannot create pipe to run filter")
			return true
		}
		 = .Call(, eval.CallCfg{Args: , From: },
			// TODO: Supply the Chan component of port 2.
			eval.EvalCfg{Ports: []*eval.Port{nil, , {File: os.Stderr}}})
		 := ()

		if  != nil {
			diag.Complainf(os.Stderr, "%s return error", )
			continue
		}
		if len() != 1 {
			diag.Complainf(os.Stderr, "filter %s should only return $true or $false", )
			continue
		}
		,  := [0].(bool)
		if ! {
			diag.Complainf(os.Stderr, "filter %s should return bool", )
			continue
		}
		if ! {
			return false
		}
	}
	return true
}

func ( int) vars.PtrVar             { return vars.FromPtr(&) }
func ( float64) vars.PtrVar       { return vars.FromPtr(&) }
func ( bool) vars.PtrVar           { return vars.FromPtr(&) }
func ( vals.List) vars.PtrVar      { return vars.FromPtr(&) }
func ( vals.Map) vars.PtrVar        { return vars.FromPtr(&) }
func ( eval.Callable) vars.PtrVar    { return vars.FromPtr(&) }
func ( bindingsMap) vars.PtrVar { return vars.FromPtr(&) }