<commit_before>package main

import (
	"regexp"

	"github.com/zyedidia/tcell"
)

var (
	// What was the last search
	lastSearch string

	// Where should we start the search down from (or up from)
	searchStart int

	// Is there currently a search in progress
	searching bool

	// Stores the history for searching
	searchHistory []string
)

// BeginSearch starts a search
func BeginSearch() {
	searchHistory = append(searchHistory, "")
	messenger.historyNum = len(searchHistory) - 1
	searching = true
	messenger.hasPrompt = true
	messenger.Message("Find: ")
}

// EndSearch stops the current search
func EndSearch() {
	searchHistory[len(searchHistory)-1] = messenger.response
	searching = false
	messenger.hasPrompt = false
	messenger.Clear()
	messenger.Reset()
	if lastSearch != "" {
		messenger.Message("^P Previous ^N Next")
	}
}

// HandleSearchEvent takes an event and a view and will do a real time match from the messenger's output
// to the current buffer. It searches down the buffer.
func HandleSearchEvent(event tcell.Event, v *View) {
	switch e := event.(type) {
	case *tcell.EventKey:
		switch e.Key() {
		case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEscape, tcell.KeyEnter:
			// Done
			EndSearch()
			return
		}
	}

	messenger.HandleEvent(event, searchHistory)

	if messenger.cursorx < 0 {
		// Done
		EndSearch()
		return
	}

	if messenger.response == "" {
		v.Cursor.ResetSelection()
		// We don't end the search though
		return
	}

	Search(messenger.response, v, true)

	return
}

// Search searches in the view for the given regex. The down bool
// specifies whether it should search down from the searchStart position
// or up from there
func Search(searchStr string, v *View, down bool) {
	if searchStr == "" {
		return
	}
	var str string
	var charPos int
	text := v.Buf.String()
	if down {
		str = string([]rune(text)[searchStart:])
		charPos = searchStart
	} else {
		str = string([]rune(text)[:searchStart])
	}
	r, err := regexp.Compile(searchStr)
	if settings["ignorecase"].(bool) {
		r, err = regexp.Compile("(?i)" + searchStr)
	}
	if err != nil {
		return
	}
	matches := r.FindAllStringIndex(str, -1)
	var match []int
	if matches == nil {
		// Search the entire buffer now
		matches = r.FindAllStringIndex(text, -1)
		charPos = 0
		if matches == nil {
			v.Cursor.ResetSelection()
			return
		}

		if !down {
			match = matches[len(matches)-1]
		} else {
			match = matches[0]
		}
		str = text
	}

	if !down {
		match = matches[len(matches)-1]
	} else {
		match = matches[0]
	}

	if match[0] == match[1] {
		return
	}

	v.Cursor.CurSelection[0] = FromCharPos(charPos+runePos(match[0], str), v.Buf)
	v.Cursor.CurSelection[1] = FromCharPos(charPos+runePos(match[1], str), v.Buf)
	if v.Relocate() {
		v.matches = Match(v)
	}
	lastSearch = searchStr
}<commit_msg>Move cursor with search selection<commit_after>package main

import (
	"regexp"

	"github.com/zyedidia/tcell"
)

var (
	// What was the last search
	lastSearch string

	// Where should we start the search down from (or up from)
	searchStart int

	// Is there currently a search in progress
	searching bool

	// Stores the history for searching
	searchHistory []string
)

// BeginSearch starts a search
func BeginSearch() {
	searchHistory = append(searchHistory, "")
	messenger.historyNum = len(searchHistory) - 1
	searching = true
	messenger.hasPrompt = true
	messenger.Message("Find: ")
}

// EndSearch stops the current search
func EndSearch() {
	searchHistory[len(searchHistory)-1] = messenger.response
	searching = false
	messenger.hasPrompt = false
	messenger.Clear()
	messenger.Reset()
	if lastSearch != "" {
		messenger.Message("^P Previous ^N Next")
	}
}

// HandleSearchEvent takes an event and a view and will do a real time match from the messenger's output
// to the current buffer. It searches down the buffer.
func HandleSearchEvent(event tcell.Event, v *View) {
	switch e := event.(type) {
	case *tcell.EventKey:
		switch e.Key() {
		case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEscape, tcell.KeyEnter:
			// Done
			EndSearch()
			return
		}
	}

	messenger.HandleEvent(event, searchHistory)

	if messenger.cursorx < 0 {
		// Done
		EndSearch()
		return
	}

	if messenger.response == "" {
		v.Cursor.ResetSelection()
		// We don't end the search though
		return
	}

	Search(messenger.response, v, true)

	return
}

// Search searches in the view for the given regex. The down bool
// specifies whether it should search down from the searchStart position
// or up from there
func Search(searchStr string, v *View, down bool) {
	if searchStr == "" {
		return
	}
	var str string
	var charPos int
	text := v.Buf.String()
	if down {
		str = string([]rune(text)[searchStart:])
		charPos = searchStart
	} else {
		str = string([]rune(text)[:searchStart])
	}
	r, err := regexp.Compile(searchStr)
	if settings["ignorecase"].(bool) {
		r, err = regexp.Compile("(?i)" + searchStr)
	}
	if err != nil {
		return
	}
	matches := r.FindAllStringIndex(str, -1)
	var match []int
	if matches == nil {
		// Search the entire buffer now
		matches = r.FindAllStringIndex(text, -1)
		charPos = 0
		if matches == nil {
			v.Cursor.ResetSelection()
			return
		}

		if !down {
			match = matches[len(matches)-1]
		} else {
			match = matches[0]
		}
		str = text
	}

	if !down {
		match = matches[len(matches)-1]
	} else {
		match = matches[0]
	}

	if match[0] == match[1] {
		return
	}

	v.Cursor.CurSelection[0] = FromCharPos(charPos+runePos(match[0], str), v.Buf)
	v.Cursor.CurSelection[1] = FromCharPos(charPos+runePos(match[1], str), v.Buf)
	v.Cursor.Loc = v.Cursor.CurSelection[1]
	if v.Relocate() {
		v.matches = Match(v)
	}
	lastSearch = searchStr
}
{'fraction_non_alphanumeric': 0.12444523344576602, 'fraction_numerical': 0.005858334812710812, 'mean_word_length': 3.5472154963680387, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '1504728', 'n_tokens_mistral': 2092, 'n_tokens_neox': 1920, 'n_words': 550}