Skip to content

Commit 7538d81

Browse files
committed
[#24193] Applied revision
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
1 parent 76212d9 commit 7538d81

3 files changed

Lines changed: 61 additions & 182 deletions

File tree

src/vulcanai/console/console.py

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,12 @@
3030

3131
from vulcanai.console.logger import VulcanAILogger
3232
from vulcanai.console.modal_screens import CheckListModal, RadioListModal, ReverseSearchModal
33+
from vulcanai.console.terminal_session import TerminalSession, TerminalSessionConfig
3334
from vulcanai.console.utils import (
3435
SpinnerHook,
3536
StreamToTextual,
3637
attach_ros_logger_to_console,
3738
common_prefix,
38-
# disable_gnome_scrollbar,
39-
# restore_gnome_scrollbar,
40-
# write_terminal_sequence,
41-
)
42-
from vulcanai.console.TerminalSession import (
43-
GnomeTerminalAdapter,
44-
TerminalSession,
45-
TerminalSessionConfig,
4639
)
4740
from vulcanai.console.widget_custom_log_text_area import CustomLogTextArea
4841
from vulcanai.console.widget_spinner import SpinnerStatus
@@ -59,79 +52,72 @@ def write(self, msg: str, color: str = "") -> None:
5952

6053

6154
class VulcanConsole(App):
62-
_vulcanai_bg_color = "#121212"
63-
6455
# CSS Styles
6556
# Two panels: left (log + input) and right (history + variables)
6657
# Right panel: 48 characters length
6758
# Left panel: fills remaining space
68-
CSS = f"""
69-
Screen {{
59+
CSS = """
60+
Screen {
7061
layout: horizontal;
71-
background: {_vulcanai_bg_color};
7262
overflow: hidden hidden;
73-
}}
63+
}
7464
75-
#root {{
65+
#root {
7666
width: 100%;
7767
height: 100%;
78-
background: {_vulcanai_bg_color};
7968
overflow: hidden hidden;
80-
}}
69+
}
8170
82-
#left {{
71+
#left {
8372
width: 1fr;
8473
layout: vertical;
85-
background: {_vulcanai_bg_color};
8674
overflow: hidden hidden;
87-
}}
75+
}
8876
89-
#right {{
77+
#right {
9078
width: 48;
9179
layout: vertical;
9280
border: tall #56AA08;
9381
padding: 0;
94-
background: {_vulcanai_bg_color};
9582
overflow: hidden hidden;
96-
}}
83+
}
9784
98-
#logcontent {{
85+
#logcontent {
9986
height: auto;
10087
min-height: 1;
10188
max-height: 1fr;
10289
border: tall #333333;
103-
background: {_vulcanai_bg_color};
10490
scrollbar-size-vertical: 0;
10591
scrollbar-size-horizontal: 0;
106-
}}
92+
}
10793
108-
#llm_spinner {{
94+
#llm_spinner {
10995
height: 0;
11096
display: none;
11197
content-align: left middle;
11298
padding-left: 2;
113-
}}
99+
}
114100
115-
#cmd {{
101+
#cmd {
116102
dock: bottom;
117-
}}
103+
}
118104
119-
#history_title {{
105+
#history_title {
120106
content-align: center middle;
121107
margin: 0;
122108
padding: 0;
123-
}}
109+
}
124110
125-
#history_scroll {{
111+
#history_scroll {
126112
height: 1fr;
127113
margin: 1;
128114
scrollbar-size-vertical: 0;
129115
scrollbar-size-horizontal: 0;
130-
}}
116+
}
131117
132-
#history {{
118+
#history {
133119
width: 100%;
134-
}}
120+
}
135121
"""
136122

137123
# Bindings for the console
@@ -1113,8 +1099,7 @@ def run_console(self) -> None:
11131099
"""
11141100

11151101
session = TerminalSession(
1116-
adapters=[GnomeTerminalAdapter()],
1117-
config=TerminalSessionConfig(bg_color=self._vulcanai_bg_color),
1102+
config=TerminalSessionConfig(),
11181103
)
11191104
with session:
11201105
self.run()
Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1-
from typing import Any, Protocol, Optional, List
2-
from dataclasses import dataclass
1+
# Copyright 2026 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
315
import os
416
import subprocess
517
import sys
18+
from dataclasses import dataclass
19+
from typing import Any, Optional, Protocol
620

721

822
def write_terminal_sequence(sequence: str) -> None:
@@ -19,25 +33,14 @@ def write_terminal_sequence(sequence: str) -> None:
1933
sys.stdout.write(sequence)
2034
sys.stdout.flush()
2135
except Exception:
22-
# best-effort: ignore
2336
pass
2437

2538

2639
class TerminalAdapter(Protocol):
2740
"""
28-
Protocol implemented by terminal-specific adapters.
29-
30-
Parent class for each terminal adapter.
31-
Done:
32-
- GNOME
33-
34-
TODO:
35-
- Terminator
36-
- Zsh
37-
- Kitty
38-
- XTerm
39-
- Alackritty
40-
- Alacritty
41+
Abstract parent class to enhance VulcanAI visualization in each terminal.
42+
Currently supported: Gnome
43+
Not yet implemented: Terminator, Zsh
4144
"""
4245

4346
name: str
@@ -48,9 +51,11 @@ def apply(self) -> Any: ...
4851

4952
def restore(self, state: Any) -> None: ...
5053

54+
5155
# region TERMINALS
5256

53-
# region gnome
57+
# region gnome
58+
5459

5560
def _run_gsettings(*args: str) -> Optional[str]:
5661
"""
@@ -90,19 +95,19 @@ def detect(self) -> bool:
9095
@brief Detect whether the current terminal is GNOME Terminal.
9196
@return ``True`` when GNOME Terminal environment markers are found.
9297
"""
93-
terminal_emulator = os.environ.get("TERMINAL_EMULATOR", "").lower()
94-
term_program = os.environ.get("TERM_PROGRAM", "").lower()
95-
return (
96-
"gnome-terminal" in terminal_emulator
97-
or "gnome-terminal" in term_program
98-
or "GNOME_TERMINAL_SCREEN" in os.environ
98+
is_gnome = (
99+
"GNOME_TERMINAL_SCREEN" in os.environ
100+
or "gnome-terminal" in os.environ.get("TERMINAL_EMULATOR", "").lower()
101+
or "gnome-terminal" in os.environ.get("TERM_PROGRAM", "").lower()
99102
)
103+
return is_gnome
100104

101105
def apply(self) -> Optional[GnomeState]:
102106
"""
103107
@brief Hide GNOME scrollbar and return state for later restoration.
104108
@return ``GnomeState`` when the change is applied/confirmed, else ``None``.
105109
"""
110+
# The return value could be None, empty string or string with just single quotes
106111
profile_id = _run_gsettings("get", "org.gnome.Terminal.ProfilesList", "default")
107112
if not profile_id:
108113
return None
@@ -137,17 +142,20 @@ def restore(self, state: Optional[GnomeState]) -> None:
137142
# endregion
138143

139144
# region TERMINATOR
145+
146+
140147
# TODO
141-
# endregion
148+
# endregion
142149

143-
# region ZSH
150+
# region ZSH
144151
# TODO
145-
# endregion
152+
# endregion
146153

147154
# endregion
148155

149156
# region SESSION
150157

158+
151159
@dataclass
152160
class TerminalSessionConfig:
153161
"""@brief Runtime options controlling generic terminal tweaks."""
@@ -165,11 +173,8 @@ class TerminalSession:
165173
Session helper that applies terminal tweaks and safely restores them.
166174
"""
167175

168-
def __init__(self, adapters: List[TerminalAdapter], config: TerminalSessionConfig):
169-
"""
170-
Build a terminal session with a list of adapters.
171-
"""
172-
self.adapters = adapters
176+
def __init__(self, config: TerminalSessionConfig):
177+
self.adapters = [GnomeTerminalAdapter()]
173178
self.config = config
174179
self._active: list[tuple[TerminalAdapter, Any]] = []
175180

@@ -225,4 +230,5 @@ def __exit__(self, exc_type, exc, tb):
225230
self.end()
226231
return False
227232

228-
# endregion
233+
234+
# endregion

src/vulcanai/console/utils.py

Lines changed: 0 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import asyncio
1717
import difflib
1818
import heapq
19-
import os
2019
import subprocess
2120
import sys
2221
import threading
@@ -361,114 +360,3 @@ def _get_suggestions(real_string_list_comp: list[str], string_comp: str) -> tupl
361360

362361

363362
# endregion
364-
365-
# region TERMINAL_CONFIG
366-
367-
368-
def write_terminal_sequence(console, sequence: str) -> None:
369-
"""
370-
Send terminal control sequence if stdout is a teletypewriter (TTY).
371-
Used for OSC / CSI compatibility tweaks.
372-
373-
OSC: Operating System Command
374-
CSI: Control Sequence Introducer
375-
"""
376-
if not sys.stdout.isatty():
377-
return
378-
379-
try:
380-
sys.stdout.write(sequence)
381-
sys.stdout.flush()
382-
except Exception as e:
383-
console.logger.log_msg(f"[error] Unsupported terminal: {e}[/error]")
384-
385-
386-
def is_gnome_terminal() -> bool:
387-
"""
388-
Return True when running inside GNOME Terminal.
389-
"""
390-
is_gnome = "GNOME_TERMINAL_SCREEN" in os.environ or \
391-
"gnome-terminal" in os.environ.get("TERMINAL_EMULATOR", "").lower() or \
392-
"gnome-terminal" in os.environ.get("TERM_PROGRAM", "").lower()
393-
return is_gnome
394-
395-
396-
def run_gsettings(*args: str) -> str | None:
397-
"""
398-
Run a gsettings command and return stdout or None on failure.
399-
"""
400-
401-
try:
402-
completed = subprocess.run(
403-
["gsettings", *args],
404-
check=False,
405-
capture_output=True,
406-
text=True,
407-
)
408-
except Exception:
409-
return None
410-
411-
if completed.returncode != 0:
412-
return None
413-
414-
return completed.stdout.strip()
415-
416-
417-
def disable_gnome_scrollbar(console) -> None:
418-
"""
419-
Temporarily set the active GNOME Terminal profile scrollbar policy to ``never``.
420-
421-
The function is intentionally best-effort:
422-
- It does nothing outside GNOME Terminal.
423-
- It does nothing if ``gsettings`` queries fail.
424-
- It stores the original profile schema and scrollbar policy on ``console`` so
425-
``restore_gnome_scrollbar()`` can revert the change when the session ends.
426-
"""
427-
428-
if not is_gnome_terminal():
429-
return
430-
431-
# GNOME returns quoted strings (for example: "'<profile-id>'").
432-
profile_id = run_gsettings("get", "org.gnome.Terminal.ProfilesList", "default")
433-
if not profile_id:
434-
return
435-
profile_id = profile_id.strip("'")
436-
if not profile_id:
437-
return
438-
439-
# Build the profile-specific schema path used by GNOME Terminal settings.
440-
schema = f"org.gnome.Terminal.Legacy.Profile:/org/gnome/terminal/legacy/profiles:/:{profile_id}/"
441-
current_policy = run_gsettings("get", schema, "scrollbar-policy")
442-
if not current_policy:
443-
return
444-
445-
console._gnome_profile_schema = schema
446-
console._gnome_scrollbar_policy_backup = current_policy
447-
448-
if current_policy != "'never'":
449-
run_gsettings("set", schema, "scrollbar-policy", "never")
450-
451-
452-
def restore_gnome_scrollbar(console) -> None:
453-
"""
454-
Restore the GNOME Terminal scrollbar policy saved by
455-
``disable_gnome_scrollbar()``.
456-
457-
If no backup values were saved, this function is a no-op.
458-
"""
459-
if not getattr(console, "_gnome_profile_schema", None) or not getattr(
460-
console, "_gnome_scrollbar_policy_backup", None):
461-
return
462-
463-
# gsettings expects the enum token without shell-style quotes.
464-
restore_value = console._gnome_scrollbar_policy_backup.strip("'")
465-
if restore_value:
466-
run_gsettings(
467-
"set",
468-
console._gnome_profile_schema,
469-
"scrollbar-policy",
470-
restore_value,
471-
)
472-
473-
474-
# endregion

0 commit comments

Comments
 (0)