summaryrefslogtreecommitdiff
path: root/internal/server
diff options
context:
space:
mode:
Diffstat (limited to 'internal/server')
-rw-r--r--internal/server/handlers/colorwriter.go42
-rw-r--r--internal/server/handlers/readcommand.go26
2 files changed, 53 insertions, 15 deletions
diff --git a/internal/server/handlers/colorwriter.go b/internal/server/handlers/colorwriter.go
index 6e0f1af..22d36c3 100644
--- a/internal/server/handlers/colorwriter.go
+++ b/internal/server/handlers/colorwriter.go
@@ -8,15 +8,17 @@ import (
// ColorWriter wraps an io.Writer and applies colors to output
type ColorWriter struct {
- writer io.Writer
- noColor bool
+ writer io.Writer
+ noColor bool
+ isFirstLine bool
}
// NewColorWriter creates a new ColorWriter
func NewColorWriter(writer io.Writer, noColor bool) *ColorWriter {
return &ColorWriter{
- writer: writer,
- noColor: noColor,
+ writer: writer,
+ noColor: noColor,
+ isFirstLine: true,
}
}
@@ -27,12 +29,26 @@ func (cw *ColorWriter) Write(p []byte) (n int, err error) {
return cw.writer.Write(p)
}
- // Apply colors
- coloredStr := brush.Colorfy(string(p))
- coloredBytes := []byte(coloredStr)
+ // Apply colors to the content
+ // The brush.Colorfy function will handle the coloring
+ inputStr := string(p)
+ coloredStr := brush.Colorfy(inputStr)
+
+ // Add color reset prefix for all lines except the first
+ var outputBytes []byte
+ if cw.isFirstLine {
+ cw.isFirstLine = false
+ outputBytes = []byte(coloredStr)
+ } else {
+ // Add color reset prefix: [39m[49m[49m[39m
+ colorResetPrefix := "\x1b[39m\x1b[49m\x1b[49m\x1b[39m"
+ outputBytes = make([]byte, len(colorResetPrefix)+len(coloredStr))
+ copy(outputBytes, colorResetPrefix)
+ copy(outputBytes[len(colorResetPrefix):], coloredStr)
+ }
// Write the colored output
- _, err = cw.writer.Write(coloredBytes)
+ _, err = cw.writer.Write(outputBytes)
if err != nil {
return 0, err
}
@@ -40,4 +56,14 @@ func (cw *ColorWriter) Write(p []byte) (n int, err error) {
// Return the original byte count to maintain compatibility
// (the caller expects n to match len(p))
return len(p), nil
+}
+
+// Close closes the ColorWriter and writes final color reset if needed
+func (cw *ColorWriter) Close() error {
+ if !cw.noColor && config.Client.TermColorsEnable && !cw.isFirstLine {
+ // Write final color reset line
+ colorResetPrefix := "\x1b[39m\x1b[49m\x1b[49m\x1b[39m"
+ cw.writer.Write([]byte(colorResetPrefix))
+ }
+ return nil
} \ No newline at end of file
diff --git a/internal/server/handlers/readcommand.go b/internal/server/handlers/readcommand.go
index 0a99aaa..901c929 100644
--- a/internal/server/handlers/readcommand.go
+++ b/internal/server/handlers/readcommand.go
@@ -147,6 +147,7 @@ func (r *readCommand) readFiles(ctx context.Context, ltx lcontext.LContext,
var output io.Writer
if r.server.serverless {
// In serverless mode, write to stdout with color support
+ // Note: plain mode means no colors, so noColor = plain
output = NewColorWriter(os.Stdout, r.server.plain)
} else {
// In client-server mode, write to server handler lines channel
@@ -209,6 +210,11 @@ func (r *readCommand) readFiles(ctx context.Context, ltx lcontext.LContext,
}
}
}
+
+ // Close the output writer if it's a ColorWriter
+ if colorWriter, ok := output.(*ColorWriter); ok {
+ colorWriter.Close()
+ }
}
// readStdin processes stdin using direct processing
@@ -217,6 +223,7 @@ func (r *readCommand) readStdin(ctx context.Context, ltx lcontext.LContext, re r
var output io.Writer
if r.server.serverless {
// In serverless mode, write to stdout with color support
+ // Note: plain mode means no colors, so noColor = plain
output = NewColorWriter(os.Stdout, r.server.plain)
} else {
// In client-server mode, write to server handler lines channel
@@ -236,6 +243,11 @@ func (r *readCommand) readStdin(ctx context.Context, ltx lcontext.LContext, re r
r.server.sendln(r.server.serverMessages, dlog.Server.Error(r.server.user,
"Error processing stdin", err))
}
+
+ // Close the output writer if it's a ColorWriter
+ if colorWriter, ok := output.(*ColorWriter); ok {
+ colorWriter.Close()
+ }
}
// isMapReduceCommand checks if this is a command that's part of a MapReduce operation
@@ -293,22 +305,22 @@ func (r *readCommand) createProcessor(re regex.Regex, ltx lcontext.LContext, out
mapProcessor, err := fs.NewMapProcessor(plain, hostname, queryStr, output)
if err != nil {
dlog.Server.Error(r.server.user, "Failed to create MapReduce processor", err)
- return fs.NewGrepProcessor(re, plain, noColor, hostname, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
+ return fs.NewGrepProcessor(re, plain, noColor, hostname, r.server.serverless, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
}
return mapProcessor, false
}
- return fs.NewGrepProcessor(re, plain, noColor, hostname, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
+ return fs.NewGrepProcessor(re, plain, noColor, hostname, r.server.serverless, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
case omode.CatClient:
if isMapReduce && queryStr != "" {
// This is a standalone MapReduce cat operation
mapProcessor, err := fs.NewMapProcessor(plain, hostname, queryStr, output)
if err != nil {
dlog.Server.Error(r.server.user, "Failed to create MapReduce processor", err)
- return fs.NewCatProcessor(plain, noColor, hostname), false
+ return fs.NewCatProcessor(plain, noColor, hostname, r.server.serverless), false
}
return mapProcessor, false
}
- return fs.NewCatProcessor(plain, noColor, hostname), false
+ return fs.NewCatProcessor(plain, noColor, hostname, r.server.serverless), false
case omode.TailClient:
if isMapReduce && queryStr != "" {
// This is a standalone MapReduce tail operation
@@ -327,14 +339,14 @@ func (r *readCommand) createProcessor(re regex.Regex, ltx lcontext.LContext, out
mapProcessor, err := fs.NewMapProcessor(plain, hostname, queryStr, output)
if err != nil {
dlog.Server.Error(r.server.user, "Failed to create MapReduce processor", err)
- return fs.NewGrepProcessor(re, plain, noColor, hostname, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
+ return fs.NewGrepProcessor(re, plain, noColor, hostname, r.server.serverless, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
}
return mapProcessor, false
}
// Fallback
- return fs.NewGrepProcessor(re, plain, noColor, hostname, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
+ return fs.NewGrepProcessor(re, plain, noColor, hostname, r.server.serverless, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
default:
// Default to grep behavior
- return fs.NewGrepProcessor(re, plain, noColor, hostname, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
+ return fs.NewGrepProcessor(re, plain, noColor, hostname, r.server.serverless, ltx.BeforeContext, ltx.AfterContext, ltx.MaxCount), false
}
}