<commit_before>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package editor

import (
	"path/filepath"
	"strings"

	"github.com/nelsam/gxui"
	"github.com/nelsam/gxui/math"
	"github.com/nelsam/gxui/mixins"
	"github.com/nelsam/gxui/themes/basic"
	"github.com/nelsam/vidar/suggestions"
)

type TabbedEditor struct {
	mixins.PanelHolder

	editors map[string]*CodeEditor

	driver gxui.Driver
	theme  *basic.Theme
	font   gxui.Font
}

func NewTabbedEditor(driver gxui.Driver, theme *basic.Theme, font gxui.Font) *TabbedEditor {
	editor := &TabbedEditor{}
	editor.Init(editor, driver, theme, font)
	return editor
}

func (e *TabbedEditor) Init(outer mixins.PanelHolderOuter, driver gxui.Driver, theme *basic.Theme, font gxui.Font) {
	e.editors = make(map[string]*CodeEditor)
	e.driver = driver
	e.theme = theme
	e.font = font
	e.PanelHolder.Init(outer, theme)
	e.SetMargin(math.Spacing{L: 0, T: 2, R: 0, B: 0})
}

func (e *TabbedEditor) Open(hiddenPrefix, path, headerText string, environ []string) *CodeEditor {
	name := relPath(hiddenPrefix, path)
	if editor, ok := e.editors[name]; ok {
		e.Select(e.PanelIndex(editor))
		e.Focus()
		return editor
	}
	editor := &CodeEditor{}
	// We want the OnRename trigger set up before the editor opens the file
	// in its Init method.
	editor.OnRename(func(newPath string) {
		e.driver.Call(func() {
			delete(e.editors, name)
			newName := relPath(hiddenPrefix, newPath)
			focused := e.SelectedPanel()
			e.editors[newName] = editor
			idx := e.PanelIndex(editor)
			if idx == -1 {
				return
			}
			e.RemovePanel(editor)
			e.AddPanelAt(editor, newName, idx)
			e.Select(e.PanelIndex(focused))
			e.Focus()
		})
	})
	editor.Init(e.driver, e.theme, e.font, path, headerText)
	editor.SetTabWidth(4)
	suggester := suggestions.NewGoCodeProvider(editor, environ)
	editor.SetSuggestionProvider(suggester)
	e.Add(name, editor)
	return editor
}

func (e *TabbedEditor) Add(name string, editor *CodeEditor) {
	e.editors[name] = editor
	e.AddPanel(editor, name)
	e.Select(e.PanelIndex(editor))
	e.Focus()
}

func (e *TabbedEditor) Focus() {
	if e.SelectedPanel() != nil {
		gxui.SetFocus(e.SelectedPanel().(gxui.Focusable))
	}
}

func (e *TabbedEditor) Files() []string {
	files := make([]string, 0, len(e.editors))
	for file := range e.editors {
		files = append(files, file)
	}
	return files
}

func (e *TabbedEditor) Editors() uint {
	return uint(len(e.editors))
}

func (e *TabbedEditor) CreatePanelTab() mixins.PanelTab {
	tab := basic.CreatePanelTab(e.theme)
	tab.OnMouseUp(func(gxui.MouseEvent) {
		e.driver.Call(e.Focus)
	})
	return tab
}

func (e *TabbedEditor) ShiftTab(delta int) {
	panels := e.PanelCount()
	if panels < 2 {
		return
	}
	current := e.PanelIndex(e.SelectedPanel())
	next := current + delta
	for next < 0 {
		next = panels - next
	}
	next = next % panels
	e.Select(next)<commit_msg>Fix my poor math skills<commit_after>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package editor

import (
	"path/filepath"
	"strings"

	"github.com/nelsam/gxui"
	"github.com/nelsam/gxui/math"
	"github.com/nelsam/gxui/mixins"
	"github.com/nelsam/gxui/themes/basic"
	"github.com/nelsam/vidar/suggestions"
)

type TabbedEditor struct {
	mixins.PanelHolder

	editors map[string]*CodeEditor

	driver gxui.Driver
	theme  *basic.Theme
	font   gxui.Font
}

func NewTabbedEditor(driver gxui.Driver, theme *basic.Theme, font gxui.Font) *TabbedEditor {
	editor := &TabbedEditor{}
	editor.Init(editor, driver, theme, font)
	return editor
}

func (e *TabbedEditor) Init(outer mixins.PanelHolderOuter, driver gxui.Driver, theme *basic.Theme, font gxui.Font) {
	e.editors = make(map[string]*CodeEditor)
	e.driver = driver
	e.theme = theme
	e.font = font
	e.PanelHolder.Init(outer, theme)
	e.SetMargin(math.Spacing{L: 0, T: 2, R: 0, B: 0})
}

func (e *TabbedEditor) Open(hiddenPrefix, path, headerText string, environ []string) *CodeEditor {
	name := relPath(hiddenPrefix, path)
	if editor, ok := e.editors[name]; ok {
		e.Select(e.PanelIndex(editor))
		e.Focus()
		return editor
	}
	editor := &CodeEditor{}
	// We want the OnRename trigger set up before the editor opens the file
	// in its Init method.
	editor.OnRename(func(newPath string) {
		e.driver.Call(func() {
			delete(e.editors, name)
			newName := relPath(hiddenPrefix, newPath)
			focused := e.SelectedPanel()
			e.editors[newName] = editor
			idx := e.PanelIndex(editor)
			if idx == -1 {
				return
			}
			e.RemovePanel(editor)
			e.AddPanelAt(editor, newName, idx)
			e.Select(e.PanelIndex(focused))
			e.Focus()
		})
	})
	editor.Init(e.driver, e.theme, e.font, path, headerText)
	editor.SetTabWidth(4)
	suggester := suggestions.NewGoCodeProvider(editor, environ)
	editor.SetSuggestionProvider(suggester)
	e.Add(name, editor)
	return editor
}

func (e *TabbedEditor) Add(name string, editor *CodeEditor) {
	e.editors[name] = editor
	e.AddPanel(editor, name)
	e.Select(e.PanelIndex(editor))
	e.Focus()
}

func (e *TabbedEditor) Focus() {
	if e.SelectedPanel() != nil {
		gxui.SetFocus(e.SelectedPanel().(gxui.Focusable))
	}
}

func (e *TabbedEditor) Files() []string {
	files := make([]string, 0, len(e.editors))
	for file := range e.editors {
		files = append(files, file)
	}
	return files
}

func (e *TabbedEditor) Editors() uint {
	return uint(len(e.editors))
}

func (e *TabbedEditor) CreatePanelTab() mixins.PanelTab {
	tab := basic.CreatePanelTab(e.theme)
	tab.OnMouseUp(func(gxui.MouseEvent) {
		e.driver.Call(e.Focus)
	})
	return tab
}

func (e *TabbedEditor) ShiftTab(delta int) {
	panels := e.PanelCount()
	if panels < 2 {
		return
	}
	current := e.PanelIndex(e.SelectedPanel())
	next := current + delta
	for next < 0 {
		next = panels + next
	}
	next = next % panels
	e.Select(next)
{'fraction_non_alphanumeric': 0.14107323658454268, 'fraction_numerical': 0.0030374620317246033, 'mean_word_length': 4.217429577464789, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3064435', 'n_tokens_mistral': 2317, 'n_tokens_neox': 2223, 'n_words': 505}