.github
workflows build.yml
content help.txt ollama.txt
queries bash.scm c.scm cpp.scm css.scm dockerfile.scm go.scm html.scm javascript.scm lua.scm markdown.scm php.scm python.scm sql.scm tsx.scm typescript.scm
samples format.txt lsp.c ollama.py test.c test.cpp test.css test.dockerfile test.html test.js test.lua test.md test.php test.py test.rb test.sh test.sql test.ts test.tsx
vendor
github.com
mattn
go-runewidth .travis.yml LICENSE README.md go.test.sh runewidth.go runewidth_appengine.go runewidth_js.go runewidth_posix.go runewidth_table.go runewidth_windows.go
mitjafelicijan
go-tree-sitter
bash binding.go parser.c parser.h scanner.c
c binding.go parser.c parser.h
cpp binding.go parser.c parser.h scanner.c
css binding.go parser.c parser.h scanner.c
dockerfile binding.go parser.c parser.h scanner.c
golang binding.go parser.c parser.h
html binding.go parser.c parser.h scanner.c tag.h
javascript binding.go parser.c parser.h scanner.c
lua binding.go parser.c parser.h scanner.c
markdown
tree-sitter-markdown binding.go parser.c parser.h scanner.c
php
tree_sitter .keep alloc.h array.h parser.h
binding.go parser.c parser.h scanner.c scanner.h
python binding.go parser.c parser.h scanner.c
sql
tree_sitter .keep alloc.h array.h parser.h
binding.go parser.c scanner.c
typescript
tsx binding.go parser.c parser.h scanner.c scanner.h
typescript binding.go parser.c parser.h scanner.c scanner.h
.gitignore LICENSE Makefile README.md alloc.c alloc.h api.h array.h atomic.h bindings.c bindings.go bindings.h bits.h clock.h error_costs.h get_changed_ranges.c get_changed_ranges.h host.h iter.go language.c language.h length.h lexer.c lexer.h node.c parser.c parser.h point.h ptypes.h query.c reduce_action.h reusable_node.h stack.c stack.h subtree.c subtree.h test_grammar.go test_grammar.js test_grammar_generate.sh tree.c tree.h tree_cursor.c tree_cursor.h umachine.h unicode.h urename.h utf.h utf16.h utf8.h wasm_store.c wasm_store.h
nsf
termbox-go AUTHORS LICENSE README.md api.go api_common.go api_windows.go collect_terminfo.py escwait.go escwait_darwin.go syscalls_darwin.go syscalls_darwin_amd64.go syscalls_dragonfly.go syscalls_freebsd.go syscalls_linux.go syscalls_netbsd.go syscalls_openbsd.go syscalls_windows.go termbox.go termbox_common.go termbox_windows.go terminfo.go terminfo_builtin.go
modules.txt
.gitignore LICENSE Makefile README.md buffer.go colors.go command.go config.go editor.go embed.go ftypes.go go.mod go.sum info.go intro.go kevent.go lsp.go main.go ollama.go replace.go syntax.go theme.go treesitter.txt
vendor/github.com/nsf/termbox-go/api.go raw
  1// +build !windows
  2
  3package termbox
  4
  5import (
  6	"fmt"
  7	"os"
  8	"os/signal"
  9	"runtime"
 10	"syscall"
 11	"time"
 12
 13	"github.com/mattn/go-runewidth"
 14)
 15
 16// public API
 17
 18// Initializes termbox library. This function should be called before any other functions.
 19// After successful initialization, the library must be finalized using 'Close' function.
 20//
 21// Example usage:
 22//      err := termbox.Init()
 23//      if err != nil {
 24//              panic(err)
 25//      }
 26//      defer termbox.Close()
 27func Init() error {
 28	if IsInit {
 29		return nil
 30	}
 31
 32	var err error
 33
 34	if runtime.GOOS == "openbsd" || runtime.GOOS == "freebsd" {
 35		out, err = os.OpenFile("/dev/tty", os.O_RDWR, 0)
 36		if err != nil {
 37			return err
 38		}
 39		in = int(out.Fd())
 40	} else {
 41		out, err = os.OpenFile("/dev/tty", os.O_WRONLY, 0)
 42		if err != nil {
 43			return err
 44		}
 45		in, err = syscall.Open("/dev/tty", syscall.O_RDONLY, 0)
 46		if err != nil {
 47			return err
 48		}
 49	}
 50
 51	err = setup_term()
 52	if err != nil {
 53		return fmt.Errorf("termbox: error while reading terminfo data: %v", err)
 54	}
 55
 56	signal.Notify(sigwinch, syscall.SIGWINCH)
 57	signal.Notify(sigio, syscall.SIGIO)
 58
 59	_, err = fcntl(in, syscall.F_SETFL, syscall.O_ASYNC|syscall.O_NONBLOCK)
 60	if err != nil {
 61		return err
 62	}
 63	_, err = fcntl(in, syscall.F_SETOWN, syscall.Getpid())
 64	if runtime.GOOS != "darwin" && err != nil {
 65		return err
 66	}
 67	err = tcgetattr(out.Fd(), &orig_tios)
 68	if err != nil {
 69		return err
 70	}
 71
 72	tios := orig_tios
 73	tios.Iflag &^= syscall_IGNBRK | syscall_BRKINT | syscall_PARMRK |
 74		syscall_ISTRIP | syscall_INLCR | syscall_IGNCR |
 75		syscall_ICRNL | syscall_IXON
 76	tios.Lflag &^= syscall_ECHO | syscall_ECHONL | syscall_ICANON |
 77		syscall_ISIG | syscall_IEXTEN
 78	tios.Cflag &^= syscall_CSIZE | syscall_PARENB
 79	tios.Cflag |= syscall_CS8
 80	tios.Cc[syscall_VMIN] = 1
 81	tios.Cc[syscall_VTIME] = 0
 82
 83	err = tcsetattr(out.Fd(), &tios)
 84	if err != nil {
 85		return err
 86	}
 87
 88	out.WriteString(funcs[t_enter_ca])
 89	out.WriteString(funcs[t_enter_keypad])
 90	out.WriteString(funcs[t_hide_cursor])
 91	out.WriteString(funcs[t_clear_screen])
 92
 93	termw, termh = get_term_size(out.Fd())
 94	back_buffer.init(termw, termh)
 95	front_buffer.init(termw, termh)
 96	back_buffer.clear()
 97	front_buffer.clear()
 98
 99	go func() {
100		buf := make([]byte, 128)
101		for {
102			select {
103			case <-sigio:
104				for {
105					n, err := syscall.Read(in, buf)
106					if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK {
107						break
108					}
109					select {
110					case input_comm <- input_event{buf[:n], err}:
111						ie := <-input_comm
112						buf = ie.data[:128]
113					case <-quit:
114						return
115					}
116				}
117			case <-quit:
118				return
119			}
120		}
121	}()
122
123	IsInit = true
124	return nil
125}
126
127// Interrupt an in-progress call to PollEvent by causing it to return
128// EventInterrupt.  Note that this function will block until the PollEvent
129// function has successfully been interrupted.
130func Interrupt() {
131	interrupt_comm <- struct{}{}
132}
133
134// Finalizes termbox library, should be called after successful initialization
135// when termbox's functionality isn't required anymore.
136func Close() {
137	if !IsInit {
138		return
139	}
140
141	quit <- 1
142	out.WriteString(funcs[t_show_cursor])
143	out.WriteString(funcs[t_sgr0])
144	out.WriteString(funcs[t_clear_screen])
145	out.WriteString(funcs[t_exit_ca])
146	out.WriteString(funcs[t_exit_keypad])
147	out.WriteString(funcs[t_exit_mouse])
148	tcsetattr(out.Fd(), &orig_tios)
149
150	out.Close()
151	syscall.Close(in)
152
153	// reset the state, so that on next Init() it will work again
154	termw = 0
155	termh = 0
156	input_mode = InputEsc
157	out = nil
158	in = 0
159	lastfg = attr_invalid
160	lastbg = attr_invalid
161	lastx = coord_invalid
162	lasty = coord_invalid
163	cursor_x = cursor_hidden
164	cursor_y = cursor_hidden
165	foreground = ColorDefault
166	background = ColorDefault
167	IsInit = false
168}
169
170// Synchronizes the internal back buffer with the terminal.
171func Flush() error {
172	// invalidate cursor position
173	lastx = coord_invalid
174	lasty = coord_invalid
175
176	update_size_maybe()
177
178	for y := 0; y < front_buffer.height; y++ {
179		line_offset := y * front_buffer.width
180		for x := 0; x < front_buffer.width; {
181			cell_offset := line_offset + x
182			back := &back_buffer.cells[cell_offset]
183			front := &front_buffer.cells[cell_offset]
184			if back.Ch < ' ' {
185				back.Ch = ' '
186			}
187			w := runewidth.RuneWidth(back.Ch)
188			if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) {
189				w = 1
190			}
191			if *back == *front {
192				x += w
193				continue
194			}
195			*front = *back
196			send_attr(back.Fg, back.Bg)
197
198			if w == 2 && x == front_buffer.width-1 {
199				// there's not enough space for 2-cells rune,
200				// let's just put a space in there
201				send_char(x, y, ' ')
202			} else {
203				send_char(x, y, back.Ch)
204				if w == 2 {
205					next := cell_offset + 1
206					front_buffer.cells[next] = Cell{
207						Ch: 0,
208						Fg: back.Fg,
209						Bg: back.Bg,
210					}
211				}
212			}
213			x += w
214		}
215	}
216	if !is_cursor_hidden(cursor_x, cursor_y) {
217		write_cursor(cursor_x, cursor_y)
218	}
219	return flush()
220}
221
222// Sets the position of the cursor. See also HideCursor().
223func SetCursor(x, y int) {
224	if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) {
225		outbuf.WriteString(funcs[t_show_cursor])
226	}
227
228	if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) {
229		outbuf.WriteString(funcs[t_hide_cursor])
230	}
231
232	cursor_x, cursor_y = x, y
233	if !is_cursor_hidden(cursor_x, cursor_y) {
234		write_cursor(cursor_x, cursor_y)
235	}
236}
237
238// The shortcut for SetCursor(-1, -1).
239func HideCursor() {
240	SetCursor(cursor_hidden, cursor_hidden)
241}
242
243// Changes cell's parameters in the internal back buffer at the specified
244// position.
245func SetCell(x, y int, ch rune, fg, bg Attribute) {
246	if x < 0 || x >= back_buffer.width {
247		return
248	}
249	if y < 0 || y >= back_buffer.height {
250		return
251	}
252
253	back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg}
254}
255
256// Returns the specified cell from the internal back buffer.
257func GetCell(x, y int) Cell {
258	return back_buffer.cells[y*back_buffer.width+x]
259}
260
261// Changes cell's character (rune) in the internal back buffer at the
262// specified position.
263func SetChar(x, y int, ch rune) {
264	if x < 0 || x >= back_buffer.width {
265		return
266	}
267	if y < 0 || y >= back_buffer.height {
268		return
269	}
270
271	back_buffer.cells[y*back_buffer.width+x].Ch = ch
272}
273
274// Changes cell's foreground attributes in the internal back buffer at
275// the specified position.
276func SetFg(x, y int, fg Attribute) {
277	if x < 0 || x >= back_buffer.width {
278		return
279	}
280	if y < 0 || y >= back_buffer.height {
281		return
282	}
283
284	back_buffer.cells[y*back_buffer.width+x].Fg = fg
285}
286
287// Changes cell's background attributes in the internal back buffer at
288// the specified position.
289func SetBg(x, y int, bg Attribute) {
290	if x < 0 || x >= back_buffer.width {
291		return
292	}
293	if y < 0 || y >= back_buffer.height {
294		return
295	}
296
297	back_buffer.cells[y*back_buffer.width+x].Bg = bg
298}
299
300// Returns a slice into the termbox's back buffer. You can get its dimensions
301// using 'Size' function. The slice remains valid as long as no 'Clear' or
302// 'Flush' function calls were made after call to this function.
303func CellBuffer() []Cell {
304	return back_buffer.cells
305}
306
307// After getting a raw event from PollRawEvent function call, you can parse it
308// again into an ordinary one using termbox logic. That is parse an event as
309// termbox would do it. Returned event in addition to usual Event struct fields
310// sets N field to the amount of bytes used within 'data' slice. If the length
311// of 'data' slice is zero or event cannot be parsed for some other reason, the
312// function will return a special event type: EventNone.
313//
314// IMPORTANT: EventNone may contain a non-zero N, which means you should skip
315// these bytes, because termbox cannot recognize them.
316//
317// NOTE: This API is experimental and may change in future.
318func ParseEvent(data []byte) Event {
319	event := Event{Type: EventKey}
320	status := extract_event(data, &event, false)
321	if status != event_extracted {
322		return Event{Type: EventNone, N: event.N}
323	}
324	return event
325}
326
327// Wait for an event and return it. This is a blocking function call. Instead
328// of EventKey and EventMouse it returns EventRaw events. Raw event is written
329// into `data` slice and Event's N field is set to the amount of bytes written.
330// The minimum required length of the 'data' slice is 1. This requirement may
331// vary on different platforms.
332//
333// NOTE: This API is experimental and may change in future.
334func PollRawEvent(data []byte) Event {
335	if len(data) == 0 {
336		panic("len(data) >= 1 is a requirement")
337	}
338
339	var event Event
340	if extract_raw_event(data, &event) {
341		return event
342	}
343
344	for {
345		select {
346		case ev := <-input_comm:
347			if ev.err != nil {
348				return Event{Type: EventError, Err: ev.err}
349			}
350
351			inbuf = append(inbuf, ev.data...)
352			input_comm <- ev
353			if extract_raw_event(data, &event) {
354				return event
355			}
356		case <-interrupt_comm:
357			event.Type = EventInterrupt
358			return event
359
360		case <-sigwinch:
361			event.Type = EventResize
362			event.Width, event.Height = get_term_size(out.Fd())
363			return event
364		}
365	}
366}
367
368// Wait for an event and return it. This is a blocking function call.
369func PollEvent() Event {
370	// Constant governing macOS specific behavior. See https://github.com/nsf/termbox-go/issues/132
371	// This is an arbitrary delay which hopefully will be enough time for any lagging
372	// partial escape sequences to come through.
373	const esc_wait_delay = 100 * time.Millisecond
374
375	var event Event
376	var esc_wait_timer *time.Timer
377	var esc_timeout <-chan time.Time
378
379	// try to extract event from input buffer, return on success
380	event.Type = EventKey
381	status := extract_event(inbuf, &event, true)
382	if event.N != 0 {
383		copy(inbuf, inbuf[event.N:])
384		inbuf = inbuf[:len(inbuf)-event.N]
385	}
386	if status == event_extracted {
387		return event
388	} else if status == esc_wait {
389		esc_wait_timer = time.NewTimer(esc_wait_delay)
390		esc_timeout = esc_wait_timer.C
391	}
392
393	for {
394		select {
395		case ev := <-input_comm:
396			if esc_wait_timer != nil {
397				if !esc_wait_timer.Stop() {
398					<-esc_wait_timer.C
399				}
400				esc_wait_timer = nil
401			}
402
403			if ev.err != nil {
404				return Event{Type: EventError, Err: ev.err}
405			}
406
407			inbuf = append(inbuf, ev.data...)
408			input_comm <- ev
409			status := extract_event(inbuf, &event, true)
410			if event.N != 0 {
411				copy(inbuf, inbuf[event.N:])
412				inbuf = inbuf[:len(inbuf)-event.N]
413			}
414			if status == event_extracted {
415				return event
416			} else if status == esc_wait {
417				esc_wait_timer = time.NewTimer(esc_wait_delay)
418				esc_timeout = esc_wait_timer.C
419			}
420		case <-esc_timeout:
421			esc_wait_timer = nil
422
423			status := extract_event(inbuf, &event, false)
424			if event.N != 0 {
425				copy(inbuf, inbuf[event.N:])
426				inbuf = inbuf[:len(inbuf)-event.N]
427			}
428			if status == event_extracted {
429				return event
430			}
431		case <-interrupt_comm:
432			event.Type = EventInterrupt
433			return event
434
435		case <-sigwinch:
436			event.Type = EventResize
437			event.Width, event.Height = get_term_size(out.Fd())
438			return event
439		}
440	}
441}
442
443// Returns the size of the internal back buffer (which is mostly the same as
444// terminal's window size in characters). But it doesn't always match the size
445// of the terminal window, after the terminal size has changed, the internal
446// back buffer will get in sync only after Clear or Flush function calls.
447func Size() (width int, height int) {
448	return termw, termh
449}
450
451// Clears the internal back buffer.
452func Clear(fg, bg Attribute) error {
453	foreground, background = fg, bg
454	err := update_size_maybe()
455	back_buffer.clear()
456	return err
457}
458
459// Sets termbox input mode. Termbox has two input modes:
460//
461// 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match
462// any known sequence. ESC means KeyEsc. This is the default input mode.
463//
464// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match
465// any known sequence. ESC enables ModAlt modifier for the next keyboard event.
466//
467// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will
468// enable mouse button press/release and drag events.
469//
470// If 'mode' is InputCurrent, returns the current input mode. See also Input*
471// constants.
472func SetInputMode(mode InputMode) InputMode {
473	if mode == InputCurrent {
474		return input_mode
475	}
476	if mode&(InputEsc|InputAlt) == 0 {
477		mode |= InputEsc
478	}
479	if mode&(InputEsc|InputAlt) == InputEsc|InputAlt {
480		mode &^= InputAlt
481	}
482	if mode&InputMouse != 0 {
483		out.WriteString(funcs[t_enter_mouse])
484	} else {
485		out.WriteString(funcs[t_exit_mouse])
486	}
487
488	input_mode = mode
489	return input_mode
490}
491
492// Sets the termbox output mode. Termbox has four output options:
493//
494// 1. OutputNormal => [1..8]
495//    This mode provides 8 different colors:
496//        black, red, green, yellow, blue, magenta, cyan, white
497//    Shortcut: ColorBlack, ColorRed, ...
498//    Attributes: AttrBold, AttrUnderline, AttrReverse
499//
500//    Example usage:
501//        SetCell(x, y, '@', ColorBlack | AttrBold, ColorRed);
502//
503// 2. Output256 => [1..256]
504//    In this mode you can leverage the 256 terminal mode:
505//    0x01 - 0x08: the 8 colors as in OutputNormal
506//    0x09 - 0x10: Color* | AttrBold
507//    0x11 - 0xe8: 216 different colors
508//    0xe9 - 0x1ff: 24 different shades of grey
509//
510//    Example usage:
511//        SetCell(x, y, '@', 184, 240);
512//        SetCell(x, y, '@', 0xb8, 0xf0);
513//
514// 3. Output216 => [1..216]
515//    This mode supports the 3rd range of the 256 mode only.
516//    But you don't need to provide an offset.
517//
518// 4. OutputGrayscale => [1..26]
519//    This mode supports the 4th range of the 256 mode
520//    and black and white colors from 3th range of the 256 mode
521//    But you don't need to provide an offset.
522//
523// In all modes, 0x00 represents the default color.
524//
525// `go run _demos/output.go` to see its impact on your terminal.
526//
527// If 'mode' is OutputCurrent, it returns the current output mode.
528//
529// Note that this may return a different OutputMode than the one requested,
530// as the requested mode may not be available on the target platform.
531func SetOutputMode(mode OutputMode) OutputMode {
532	if mode == OutputCurrent {
533		return output_mode
534	}
535
536	output_mode = mode
537	return output_mode
538}
539
540// Sync comes handy when something causes desync between termbox's understanding
541// of a terminal buffer and the reality. Such as a third party process. Sync
542// forces a complete resync between the termbox and a terminal, it may not be
543// visually pretty though.
544func Sync() error {
545	front_buffer.clear()
546	err := send_clear()
547	if err != nil {
548		return err
549	}
550
551	return Flush()
552}