diff --git a/buffer/buffer.go b/buffer/buffer.go index cb4544f..80670e8 100644 --- a/buffer/buffer.go +++ b/buffer/buffer.go @@ -883,6 +883,13 @@ func (buffer *Buffer) Clear() { buffer.SetPosition(0, 0) // do we need to set position? } +func (buffer *Buffer) ReallyClear() { + defer buffer.emitDisplayChange() + buffer.lines = []Line{} + buffer.terminalState.SetScrollOffset(0) + buffer.SetPosition(0, 0) +} + // creates if necessary func (buffer *Buffer) getCurrentLine() *Line { return buffer.getViewLine(buffer.terminalState.cursorY) diff --git a/config/actions.go b/config/actions.go index 21bfe0c..fcfa1cc 100644 --- a/config/actions.go +++ b/config/actions.go @@ -9,4 +9,5 @@ const ( ActionReportBug UserAction = "report" ActionToggleDebug UserAction = "debug" ActionToggleSlomo UserAction = "slomo" + ActionBufferClear UserAction = "buffer-clear" ) diff --git a/config/defaults.go b/config/defaults.go index 23f4b26..bc0557c 100644 --- a/config/defaults.go +++ b/config/defaults.go @@ -39,6 +39,7 @@ func init() { DefaultConfig.KeyMapping[string(ActionToggleDebug)] = addMod("d") DefaultConfig.KeyMapping[string(ActionToggleSlomo)] = addMod(";") DefaultConfig.KeyMapping[string(ActionReportBug)] = addMod("r") + DefaultConfig.KeyMapping[string(ActionBufferClear)] = addMod("k") } func addMod(keys string) string { diff --git a/gui/actions.go b/gui/actions.go index 4134f7c..ba611c1 100644 --- a/gui/actions.go +++ b/gui/actions.go @@ -15,6 +15,7 @@ var actionMap = map[config.UserAction]func(gui *GUI){ config.ActionSearch: actionSearchSelection, config.ActionToggleSlomo: actionToggleSlomo, config.ActionReportBug: actionReportBug, + config.ActionBufferClear: actionBufferClear, } func actionCopy(gui *GUI) { @@ -50,3 +51,7 @@ func actionToggleSlomo(gui *GUI) { func actionReportBug(gui *GUI) { gui.launchTarget("https://github.com/liamg/aminal/issues/new/choose") } + +func actionBufferClear(gui *GUI) { + gui.terminal.ReallyClear() +} diff --git a/platform/interfaces.go b/platform/interfaces.go index a88967c..88004c6 100644 --- a/platform/interfaces.go +++ b/platform/interfaces.go @@ -19,4 +19,5 @@ type Pty interface { Resize(x int, y int) error CreateGuestProcess(imagePath string) (Process, error) GetPlatformDependentSettings() PlatformDependentSettings + Clear() } diff --git a/platform/unixpty.go b/platform/unixpty.go index 2f043f9..a4d0e02 100644 --- a/platform/unixpty.go +++ b/platform/unixpty.go @@ -86,6 +86,10 @@ func (pty *unixPty) GetPlatformDependentSettings() PlatformDependentSettings { return pty.platformDependentSettings } +func (pty *unixPty) Clear() { + // do nothing for unix +} + func NewPty(x, y int) (Pty, error) { innerPty, innerTty, err := pty.Open() if err != nil { diff --git a/platform/winpty.go b/platform/winpty.go index b792f85..4bc1dc2 100644 --- a/platform/winpty.go +++ b/platform/winpty.go @@ -8,6 +8,7 @@ import ( "time" "fmt" + "github.com/MaxRis/w32" ) @@ -98,6 +99,7 @@ type winConPty struct { innerInPipe syscall.Handle innerOutPipe syscall.Handle hcon uintptr + processID uint32 // required to obtain old-style console handle (for standard console functions) platformDependentSettings PlatformDependentSettings } @@ -140,6 +142,8 @@ func (pty *winConPty) CreateGuestProcess(imagePath string) (Process, error) { return nil, err } + pty.processID = process.processID + err = setupChildConsole(C.DWORD(process.processID), C.STD_OUTPUT_HANDLE, C.ENABLE_PROCESSED_OUTPUT|C.ENABLE_WRAP_AT_EOL_OUTPUT) if err != nil { process.Close() @@ -192,6 +196,50 @@ func (pty *winConPty) GetPlatformDependentSettings() PlatformDependentSettings { return pty.platformDependentSettings } +func (pty *winConPty) Clear() { + C.FreeConsole() + defer C.AttachConsole(^C.DWORD(0)) // attach to parent process console + + if C.AttachConsole(C.DWORD(pty.processID)) == 0 { + return + } + defer C.FreeConsole() + hConsole := C.GetStdHandle(C.STD_OUTPUT_HANDLE) + + var coordScreen C.COORD + coordScreen.X = 0 + coordScreen.Y = 0 + var cCharsWritten C.DWORD + var csbi C.CONSOLE_SCREEN_BUFFER_INFO + + // Get the number of character cells in the current buffer. + if C.GetConsoleScreenBufferInfo(hConsole, &csbi) != C.BOOL(0) { + + dwConSize := C.DWORD(csbi.dwSize.X * csbi.dwSize.Y) + + // Fill the entire screen with blanks. + C.FillConsoleOutputCharacterA(hConsole, // Handle to console screen buffer + ' ', // Character to write to the buffer + dwConSize, // Number of cells to write + coordScreen, // Coordinates of first cell + &cCharsWritten) // Receive number of characters written + + // Get the current text attribute. + if C.GetConsoleScreenBufferInfo(hConsole, &csbi) != C.BOOL(0) { + // Set the buffer's attributes accordingly. + + C.FillConsoleOutputAttribute(hConsole, // Handle to console screen buffer + csbi.wAttributes, // Character attributes to use + dwConSize, // Number of cells to set attribute + coordScreen, // Coordinates of first cell + &cCharsWritten) // Receive number of characters written + } + } + + // Put the cursor at its home coordinates. + C.SetConsoleCursorPosition(hConsole, coordScreen) +} + // NewPty creates a new instance of a Pty implementation for Windows on a newly allocated ConPTY func NewPty(x, y int) (pty Pty, err error) { if !ptyInitSucceeded { diff --git a/terminal/terminal.go b/terminal/terminal.go index 6449ff5..f9c6ce0 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -353,6 +353,11 @@ func (terminal *Terminal) Clear() { terminal.ActiveBuffer().Clear() } +func (terminal *Terminal) ReallyClear() { + terminal.pty.Clear() + terminal.ActiveBuffer().ReallyClear() +} + func (terminal *Terminal) GetSize() (int, int) { return int(terminal.size.Width), int(terminal.size.Height) }