1212#include " ui_manager.h"
1313#include " uistate.h"
1414
15+ #include < algorithm>
16+
1517namespace cata
1618{
1719
20+ namespace
21+ {
22+
23+ struct numbered_prompt_line {
24+ int number = 0 ;
25+ std::string text;
26+ };
27+
28+ auto split_prompt_lines ( const std::string &text ) -> std::vector<std::string>
29+ {
30+ auto lines = std::vector<std::string>();
31+ auto start = std::string::size_type{ 0 };
32+ while ( start <= text.size () ) {
33+ const auto end = text.find ( ' \n ' , start );
34+ if ( end == std::string::npos ) {
35+ lines.push_back ( text.substr ( start ) );
36+ break ;
37+ }
38+ lines.push_back ( text.substr ( start, end - start ) );
39+ start = end + 1 ;
40+ if ( start == text.size () ) {
41+ lines.emplace_back ();
42+ break ;
43+ }
44+ }
45+ if ( lines.empty () ) {
46+ lines.emplace_back ();
47+ }
48+ return lines;
49+ }
50+
51+ auto format_line_number ( const int line_number, const int width ) -> std::string
52+ {
53+ if ( line_number <= 0 ) {
54+ return std::string ( width, ' ' );
55+ }
56+ auto rendered = std::to_string ( line_number );
57+ const auto padding = width - static_cast <int >( rendered.size () );
58+ if ( padding > 0 ) {
59+ rendered.insert ( rendered.begin (), padding, ' ' );
60+ }
61+ return rendered;
62+ }
63+
64+ auto build_numbered_prompt_lines ( const std::string &text, const int content_width )
65+ -> std::vector<numbered_prompt_line>
66+ {
67+ auto lines = std::vector<numbered_prompt_line>();
68+ const auto logical_lines = split_prompt_lines ( text );
69+ auto line_number = 1 ;
70+ for ( auto i = 0 ; i < static_cast <int >( logical_lines.size () ); ++i ) {
71+ auto folded = foldstring ( logical_lines[i], content_width );
72+ if ( folded.empty () ) {
73+ folded.emplace_back ();
74+ }
75+ for ( auto j = 0 ; j < static_cast <int >( folded.size () ); ++j ) {
76+ lines.push_back ( numbered_prompt_line{
77+ .number = j == 0 ? line_number : 0 ,
78+ .text = std::move ( folded[j] ),
79+ } );
80+ }
81+ ++line_number;
82+ }
83+ return lines;
84+ }
85+
86+ } // namespace
87+
1888struct folded_log_msg {
1989 bool is_head = false ;
2090 LuaLogLevel level;
@@ -85,6 +155,7 @@ void show_lua_console_impl()
85155 ctxt.register_action ( " EDIT" );
86156 ctxt.register_action ( " QUIT" );
87157 ctxt.register_action ( " LUA_RELOAD" );
158+ ctxt.register_action ( " TOGGLE_EXPANDED" );
88159 ctxt.register_action ( " HISTORY_UP" );
89160 ctxt.register_action ( " HISTORY_DOWN" );
90161 ctxt.register_action ( " SCROLL_UP" );
@@ -94,9 +165,9 @@ void show_lua_console_impl()
94165
95166 ui_adaptor ui;
96167
97- constexpr int CURRENT_INPUT = -1 ;
98- constexpr int scroll_speed = 5 ;
99- constexpr int input_area_size = 5 ;
168+ constexpr auto CURRENT_INPUT = -1 ;
169+ constexpr auto scroll_speed = 5 ;
170+ constexpr auto collapsed_input_area_size = 5 ;
100171
101172 point win_pos;
102173 point win_size;
@@ -105,8 +176,22 @@ void show_lua_console_impl()
105176 point prompt_pos;
106177 point prompt_size;
107178
108- int log_scroll_pos = 0 ;
109- std::vector<folded_log_msg> log_folded;
179+ auto log_scroll_pos = 0 ;
180+ auto log_folded = std::vector<folded_log_msg>();
181+
182+ auto use_expanded_view = false ;
183+ auto input_area_size = collapsed_input_area_size;
184+
185+ const auto get_input_area_size = [&]( const point & window_size,
186+ const bool expanded ) -> int {
187+ const auto max_input_size = std::max ( collapsed_input_area_size, window_size.y - 8 );
188+ if ( !expanded )
189+ {
190+ return collapsed_input_area_size;
191+ }
192+ const auto target_size = std::max ( collapsed_input_area_size, window_size.y / 2 );
193+ return std::min ( max_input_size, target_size );
194+ };
110195
111196 const auto create_string_editor = [&]() {
112197 // Offset by one for the scrollbar
@@ -120,11 +205,12 @@ void show_lua_console_impl()
120205 std::string current_input;
121206 int history_cursor = CURRENT_INPUT;
122207
123- bool is_editing = false ;
208+ auto is_editing = false ;
124209
125210 ui.on_screen_resize ( [&]( ui_adaptor & ui ) {
126211 win_size = point ( TERMX, TERMY );
127212 win_pos = point ( ( TERMX - win_size.x ) / 2 , ( TERMY - win_size.y ) / 2 );
213+ input_area_size = get_input_area_size ( win_size, use_expanded_view );
128214 prompt_size = point ( win_size.x - 3 , input_area_size );
129215 prompt_pos = win_pos + point ( 2 , win_size.y - input_area_size - 1 );
130216 log_pos = win_pos + point_south_east;
@@ -164,7 +250,10 @@ void show_lua_console_impl()
164250 _ ( " Press Up/Down arrows to select from history" )
165251 );
166252 mvwprintz ( w_console, point ( 1 , separator_y - 1 ), c_light_gray,
167- _ ( " Press PgUp/PgDn/Home/End to scroll output window" )
253+ string_format (
254+ _ ( " Press PgUp/PgDn/Home/End to scroll output window, %s to toggle expanded input view" ),
255+ ctxt.get_desc ( " TOGGLE_EXPANDED" )
256+ )
168257 );
169258 }
170259
@@ -203,13 +292,38 @@ void show_lua_console_impl()
203292
204293 werase ( w_prompt );
205294
206- print_scrollable (
207- w_prompt,
208- 0 ,
209- history_cursor == CURRENT_INPUT ? current_input : get_input_history ()[history_cursor],
210- c_light_gray,
211- " "
212- );
295+ const auto prompt_text =
296+ history_cursor == CURRENT_INPUT ? current_input : get_input_history ()[history_cursor];
297+ const auto prompt_line_count = std::max (
298+ 1 ,
299+ static_cast <int >( split_prompt_lines ( prompt_text ).size () )
300+ );
301+ const auto line_number_width =
302+ std::max ( 2 , static_cast <int >( std::to_string ( prompt_line_count ).size () ) );
303+ const auto gutter_width = line_number_width + 1 ;
304+ const auto content_width = std::max ( 1 , prompt_size.x - gutter_width );
305+ const auto prompt_lines = build_numbered_prompt_lines ( prompt_text, content_width );
306+ const auto prompt_start_line =
307+ std::max ( 0 , static_cast <int >( prompt_lines.size () ) - prompt_size.y );
308+ const auto visible_lines =
309+ std::min ( prompt_size.y , static_cast <int >( prompt_lines.size () ) - prompt_start_line );
310+ for ( auto i = 0 ; i < visible_lines; ++i ) {
311+ const auto &line = prompt_lines[prompt_start_line + i];
312+ mvwprintz (
313+ w_prompt,
314+ point ( 0 , i ),
315+ c_light_gray,
316+ " %s" ,
317+ format_line_number ( line.number , line_number_width )
318+ );
319+ mvwprintz (
320+ w_prompt,
321+ point ( gutter_width, i ),
322+ c_light_gray,
323+ " %s" ,
324+ line.text
325+ );
326+ }
213327
214328 wnoutrefresh ( w_prompt );
215329 } );
@@ -270,7 +384,10 @@ void show_lua_console_impl()
270384 ui.invalidate_ui ();
271385 string_editor_window ew (
272386 create_string_editor,
273- history_cursor == CURRENT_INPUT ? current_input : get_input_history ()[history_cursor]
387+ history_cursor == CURRENT_INPUT ? current_input : get_input_history ()[history_cursor],
388+ string_editor_window::string_editor_window_options{
389+ .show_line_numbers = true ,
390+ }
274391 );
275392 std::pair<bool , std::string> res = ew.query_string ();
276393 is_editing = false ;
@@ -289,6 +406,10 @@ void show_lua_console_impl()
289406 ui.invalidate_ui ();
290407 log_invalidated = true ;
291408 reload_lua_code ();
409+ } else if ( act == " TOGGLE_EXPANDED" ) {
410+ use_expanded_view = !use_expanded_view;
411+ ui.mark_resize ();
412+ ui.invalidate_ui ();
292413 }
293414 }
294415}
0 commit comments