2424#include <slash/slash.h>
2525#include <slash/optparse.h>
2626#include <slash/completer.h>
27+ #include <slash/statusline.h>
2728
2829#include <dlfcn.h>
2930#include <stdio.h>
4849#include <sys/select.h>
4950#endif
5051
52+ #ifdef SLASH_HAVE_TERMIOS_H
53+ #include <sys/ioctl.h>
54+ #endif
55+
5156#include "builtins.h"
5257
5358/* Terminal codes */
@@ -137,31 +142,92 @@ static int slash_rawmode_disable(struct slash *slash)
137142 return 0 ;
138143}
139144
145+ static void slash_statusline_activate (struct slash * slash )
146+ {
147+ #ifdef SLASH_HAVE_TERMIOS_H
148+ struct winsize ws ;
149+ if (ioctl (slash -> fd_write , TIOCGWINSZ , & ws ) == -1 )
150+ return ;
151+
152+ int rows = ws .ws_row ;
153+ char esc [32 ];
154+
155+ //Set scroll region to all rows except the last.
156+ //DECSTBM resets cursor to (1,1) per VT100 spec.
157+ snprintf (esc , sizeof (esc ), "\033[1;%dr" , rows - 1 );
158+ slash_write (slash , esc , strlen (esc ));
159+
160+ // Move cursor to bottom of scroll region (prompt row)
161+ snprintf (esc , sizeof (esc ), "\033[%d;1H" , rows - 1 );
162+ slash_write (slash , esc , strlen (esc ));
163+
164+ // Draw statusline on the reserved bottom row
165+ slash_write (slash , "\0337" , 2 ); // DEC save cursor
166+ snprintf (esc , sizeof (esc ), "\033[%d;1H" , rows );
167+ slash_write (slash , esc , strlen (esc ));
168+ slash_statusline_render (slash );
169+ slash_write (slash , "\0338" , 2 ); // DEC restore cursor
170+
171+ slash -> statusline_enabled = true;
172+ slash -> statusline_rows = rows ;
173+ #endif
174+ }
175+
176+ static void slash_statusline_deactivate (struct slash * slash )
177+ {
178+ #ifdef SLASH_HAVE_TERMIOS_H
179+ if (!slash -> statusline_enabled )
180+ return ;
181+
182+ char esc [32 ];
183+
184+ // Save cursor so we can restore after scroll region reset
185+ slash_write (slash , "\0337" , 2 );
186+
187+ // Clear the statusline row
188+ snprintf (esc , sizeof (esc ), "\033[%d;1H\033[K" , slash -> statusline_rows );
189+ slash_write (slash , esc , strlen (esc ));
190+
191+ // Reset scroll region to full terminal (moves cursor to 1,1)
192+ slash_write (slash , "\033[r" , 3 );
193+
194+ // Restore cursor to where it was
195+ slash_write (slash , "\0338" , 2 );
196+
197+ slash -> statusline_enabled = false;
198+ #endif
199+ }
200+
140201static int slash_configure_term (struct slash * slash )
141202{
142203 if (slash_rawmode_enable (slash ) < 0 )
143204 return - ENOTTY ;
144205
206+ if (slash_statusline_count () > 0 )
207+ slash_statusline_activate (slash );
208+
145209 return 0 ;
146210}
147211
148212static int slash_restore_term (struct slash * slash )
149213{
214+ slash_statusline_deactivate (slash );
215+
150216 if (slash_rawmode_disable (slash ) < 0 )
151217 return - ENOTTY ;
152218
153219 return 0 ;
154220}
155221
156222static int slash_wait_select (void * slashp , unsigned int ms );
157- void slash_acquire_std_in_out (struct slash * slash ) {
223+ void slash_acquire_std_in_out (struct slash * slash ) {
158224 slash_configure_term (slash );
159225#ifdef SLASH_HAVE_SELECT
160226 slash -> waitfunc = slash_wait_select ;
161227#endif
162228}
163229
164- void slash_release_std_in_out (struct slash * slash ) {
230+ void slash_release_std_in_out (struct slash * slash ) {
165231 slash_restore_term (slash );
166232#ifdef SLASH_HAVE_SELECT
167233 slash -> waitfunc = NULL ;
@@ -175,7 +241,11 @@ int slash_write(struct slash *slash, const char *buf, size_t count)
175241
176242static int slash_read (struct slash * slash , void * buf , size_t count )
177243{
178- return read (slash -> fd_read , buf , count );
244+ int ret ;
245+ do {
246+ ret = read (slash -> fd_read , buf , count );
247+ } while (ret < 0 && errno == EINTR );
248+ return ret ;
179249}
180250
181251int slash_putchar (struct slash * slash , char c )
@@ -813,6 +883,29 @@ int slash_refresh(struct slash *slash, int printtime)
813883 if (slash_write (slash , esc , strlen (esc )) < 0 )
814884 return -1 ;
815885
886+ /* Update statusline on the fixed bottom row */
887+ #ifdef SLASH_HAVE_TERMIOS_H
888+ if (slash_statusline_count () > 0 ) {
889+ if (!slash -> statusline_enabled ) {
890+ slash_statusline_activate (slash );
891+ /* Activation moved cursor; re-run refresh at new position */
892+ return slash_refresh (slash , printtime );
893+ }
894+ struct winsize ws ;
895+ if (ioctl (slash -> fd_write , TIOCGWINSZ , & ws ) == 0 &&
896+ ws .ws_row != slash -> statusline_rows ) {
897+ slash_statusline_activate (slash );
898+ return slash_refresh (slash , printtime );
899+ }
900+ char pos [16 ];
901+ slash_write (slash , "\0337" , 2 ); /* DEC save cursor */
902+ snprintf (pos , sizeof (pos ), "\033[%d;1H" , slash -> statusline_rows );
903+ slash_write (slash , pos , strlen (pos ));
904+ slash_statusline_render (slash );
905+ slash_write (slash , "\0338" , 2 ); /* DEC restore cursor */
906+ }
907+ #endif
908+
816909 return 0 ;
817910}
818911
@@ -918,17 +1011,24 @@ static void slash_swap(struct slash *slash)
9181011void slash_clear_screen (struct slash * slash ) {
9191012 const char * esc = ESCAPE ("H" ) ESCAPE ("2J" );
9201013 slash_write (slash , esc , strlen (esc ));
1014+ /* Force statusline scroll region re-setup on next refresh */
1015+ slash -> statusline_enabled = false;
9211016}
9221017
9231018void slash_sigint (struct slash * slash , int signum ) {
9241019 if (slash -> busy ) {
9251020 slash -> signal = signum ;
9261021 } else {
927- slash_reset (slash );
1022+ slash_reset (slash );
9281023 slash_refresh (slash , 0 );
9291024 }
9301025}
9311026
1027+ void slash_sigwinch (struct slash * slash ) {
1028+ slash -> statusline_enabled = false; /* force scroll region re-setup */
1029+ slash_refresh (slash , 0 );
1030+ }
1031+
9321032#include <stdlib.h>
9331033char * slash_readline (struct slash * slash )
9341034{
@@ -1153,6 +1253,11 @@ int slash_loop(struct slash *slash)
11531253 if (!slash_line_empty (line , strlen (line ))) {
11541254 /* Run command */
11551255 ret = slash_execute (slash , line );
1256+ #ifdef SLASH_HAVE_TERMIOS_H
1257+ if (ret != SLASH_SUCCESS ) {
1258+ slash_statusline_set ("slash" , {.type = SLASH_STATUS_ERROR },"FAILED: %s" , line );
1259+ }
1260+ #endif
11561261 if (ret == SLASH_EXIT )
11571262 break ;
11581263 }
@@ -1239,6 +1344,7 @@ void slash_create_static(struct slash *slash, char * line_buf, size_t line_size,
12391344 slash -> cmd_list = 0 ;
12401345
12411346 slash -> complete_in_completion = true;
1347+ slash -> statusline_enabled = false;
12421348
12431349 tcgetattr (slash -> fd_read , & slash -> original );
12441350}
0 commit comments