<commit_before>package terminal

import (
	"fmt"
	"io"
	"net/rpc"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"sync"
	"syscall"

	"github.com/peterh/liner"

	"github.com/go-delve/delve/pkg/config"
	"github.com/go-delve/delve/pkg/terminal/starbind"
	"github.com/go-delve/delve/service"
	"github.com/go-delve/delve/service/api"
)

const (
	historyFile                 string = ".dbg_history"
	terminalHighlightEscapeCode string = "\033[%2dm"
	terminalResetEscapeCode     string = "\033[0m"
)

const (
	ansiBlack     = 30
	ansiRed       = 31
	ansiGreen     = 32
	ansiYellow    = 33
	ansiBlue      = 34
	ansiMagenta   = 35
	ansiCyan      = 36
	ansiWhite     = 37
	ansiBrBlack   = 90
	ansiBrRed     = 91
	ansiBrGreen   = 92
	ansiBrYellow  = 93
	ansiBrBlue    = 94
	ansiBrMagenta = 95
	ansiBrCyan    = 96
	ansiBrWhite   = 97
)

// Term represents the terminal running dlv.
type Term struct {
	client   service.Client
	conf     *config.Config
	prompt   string
	line     *liner.State
	cmds     *Commands
	dumb     bool
	stdout   io.Writer
	InitFile string
	displays []string

	historyFile *os.File

	starlarkEnv *starbind.Env

	// quitContinue is set to true by exitCommand to signal that the process
	// should be resumed before quitting.
	quitContinue bool

	quittingMutex sync.Mutex
	quitting      bool
}

// New returns a new Term.
func New(client service.Client, conf *config.Config) *Term {
	cmds := DebugCommands(client)
	if conf != nil && conf.Aliases != nil {
		cmds.Merge(conf.Aliases)
	}

	if conf == nil {
		conf = &config.Config{}
	}

	var w io.Writer

	dumb := strings.ToLower(os.Getenv("TERM")) == "dumb"
	if dumb {
		w = os.Stdout
	} else {
		w = getColorableWriter()
	}

	if (conf.SourceListLineColor > ansiWhite &&
		conf.SourceListLineColor < ansiBrBlack) ||
		conf.SourceListLineColor < ansiBlack ||
		conf.SourceListLineColor > ansiBrWhite {
		conf.SourceListLineColor = ansiBlue
	}

	t := &Term{
		client: client,
		conf:   conf,
		prompt: "(dlv) ",
		line:   liner.NewLiner(),
		cmds:   cmds,
		dumb:   dumb,
		stdout: w,
	}

	if client != nil {
		lcfg := t.loadConfig()
		client.SetReturnValuesLoadConfig(&lcfg)
	}

	t.starlarkEnv = starbind.New(starlarkContext{t})
	return t
}

// Close returns the terminal to its previous mode.
func (t *Term) Close() {
	t.line.Close()
}

func (t *Term) sigintGuard(ch <-chan os.Signal, multiClient bool) {
	for range ch {
		t.starlarkEnv.Cancel()
		state, err := t.client.GetStateNonBlocking()
		if err == nil && state.Recording {
			fmt.Printf("received SIGINT, stopping recording (will not forward signal)\n")
			err := t.client.StopRecording()
			if err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
			}
			continue
		}
		if multiClient {
			answer, err := t.line.Prompt("Would you like to [s]top the target or [q]uit this client, leaving the target running [s/q]? ")
			if err != nil {
				fmt.Fprintf(os.Stderr, "%v", err)
				continue
			}
			answer = strings.TrimSpace(answer)
			switch answer {
			case "s":
				_, err := t.client.Halt()
				if err != nil {
					fmt.Fprintf(os.Stderr, "%v", err)
				}
			case "q":
				t.quittingMutex.Lock()
				t.quitting = true
				t.quittingMutex.Unlock()
				err := t.client.Disconnect(false)
				if err != nil {
					fmt.Fprintf(os.Stderr, "%v", err)
				} else {
					t.Close()
				}
			default:
				fmt.Println("only s or q allowed")<commit_msg>terminal: clarify Ctrl-C options with multiclient servers<commit_after>package terminal

import (
	"fmt"
	"io"
	"net/rpc"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"sync"
	"syscall"

	"github.com/peterh/liner"

	"github.com/go-delve/delve/pkg/config"
	"github.com/go-delve/delve/pkg/terminal/starbind"
	"github.com/go-delve/delve/service"
	"github.com/go-delve/delve/service/api"
)

const (
	historyFile                 string = ".dbg_history"
	terminalHighlightEscapeCode string = "\033[%2dm"
	terminalResetEscapeCode     string = "\033[0m"
)

const (
	ansiBlack     = 30
	ansiRed       = 31
	ansiGreen     = 32
	ansiYellow    = 33
	ansiBlue      = 34
	ansiMagenta   = 35
	ansiCyan      = 36
	ansiWhite     = 37
	ansiBrBlack   = 90
	ansiBrRed     = 91
	ansiBrGreen   = 92
	ansiBrYellow  = 93
	ansiBrBlue    = 94
	ansiBrMagenta = 95
	ansiBrCyan    = 96
	ansiBrWhite   = 97
)

// Term represents the terminal running dlv.
type Term struct {
	client   service.Client
	conf     *config.Config
	prompt   string
	line     *liner.State
	cmds     *Commands
	dumb     bool
	stdout   io.Writer
	InitFile string
	displays []string

	historyFile *os.File

	starlarkEnv *starbind.Env

	// quitContinue is set to true by exitCommand to signal that the process
	// should be resumed before quitting.
	quitContinue bool

	quittingMutex sync.Mutex
	quitting      bool
}

// New returns a new Term.
func New(client service.Client, conf *config.Config) *Term {
	cmds := DebugCommands(client)
	if conf != nil && conf.Aliases != nil {
		cmds.Merge(conf.Aliases)
	}

	if conf == nil {
		conf = &config.Config{}
	}

	var w io.Writer

	dumb := strings.ToLower(os.Getenv("TERM")) == "dumb"
	if dumb {
		w = os.Stdout
	} else {
		w = getColorableWriter()
	}

	if (conf.SourceListLineColor > ansiWhite &&
		conf.SourceListLineColor < ansiBrBlack) ||
		conf.SourceListLineColor < ansiBlack ||
		conf.SourceListLineColor > ansiBrWhite {
		conf.SourceListLineColor = ansiBlue
	}

	t := &Term{
		client: client,
		conf:   conf,
		prompt: "(dlv) ",
		line:   liner.NewLiner(),
		cmds:   cmds,
		dumb:   dumb,
		stdout: w,
	}

	if client != nil {
		lcfg := t.loadConfig()
		client.SetReturnValuesLoadConfig(&lcfg)
	}

	t.starlarkEnv = starbind.New(starlarkContext{t})
	return t
}

// Close returns the terminal to its previous mode.
func (t *Term) Close() {
	t.line.Close()
}

func (t *Term) sigintGuard(ch <-chan os.Signal, multiClient bool) {
	for range ch {
		t.starlarkEnv.Cancel()
		state, err := t.client.GetStateNonBlocking()
		if err == nil && state.Recording {
			fmt.Printf("received SIGINT, stopping recording (will not forward signal)\n")
			err := t.client.StopRecording()
			if err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
			}
			continue
		}
		if multiClient {
			answer, err := t.line.Prompt("Would you like to [p]ause the target (returning to Delve's prompt) or [q]uit this client (leaving the target running) [p/q]? ")
			if err != nil {
				fmt.Fprintf(os.Stderr, "%v", err)
				continue
			}
			answer = strings.TrimSpace(answer)
			switch answer {
			case "p":
				_, err := t.client.Halt()
				if err != nil {
					fmt.Fprintf(os.Stderr, "%v", err)
				}
			case "q":
				t.quittingMutex.Lock()
				t.quitting = true
				t.quittingMutex.Unlock()
				err := t.client.Disconnect(false)
				if err != nil {
					fmt.Fprintf(os.Stderr, "%v", err)
				} else {
					t.Close()
				}
			default:
				fmt.Println("only s or q allowed")
{'fraction_non_alphanumeric': 0.12603305785123967, 'fraction_numerical': 0.011806375442739079, 'mean_word_length': 2.9128175519630486, 'pattern_counts': {'":': 4, '<': 9, '<?xml version=': 0, '>': 7, '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': '6685019', 'n_tokens_mistral': 2859, 'n_tokens_neox': 2534, 'n_words': 609}