File size: 7,354 Bytes
ffc07fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
! Layer 15 β€” Sovereign IDE Application Shell
! Session state, workspace, main event loop, BOB context slot
! Maps to: bob-ide, bob-orchestrator
MODULE sovereign_shell
  USE iso_c_binding
  USE sovereign_runtime, ONLY: runtime_init, runtime_teardown, runtime_panic, str_intern
  IMPLICIT NONE
  PRIVATE

  ! ── Workspace descriptor ─────────────────────────────────────────────────
  INTEGER, PARAMETER :: MAX_OPEN_FILES = 512
  INTEGER, PARAMETER :: MAX_PANELS     = 16

  TYPE :: panel_t
    REAL    :: x = 0.0, y = 0.0, w = 1.0, h = 1.0
    INTEGER :: buffer_idx = 0
    LOGICAL :: active     = .FALSE.
  END TYPE panel_t

  TYPE :: workspace_t
    INTEGER(C_INT32_T) :: root_path_id     = 0
    INTEGER(C_INT32_T) :: open_files(MAX_OPEN_FILES)
    INTEGER            :: open_count       = 0
    TYPE(panel_t)      :: panels(MAX_PANELS)
    INTEGER            :: panel_count      = 1
    INTEGER            :: active_panel     = 1
    LOGICAL            :: dirty            = .FALSE.
  END TYPE workspace_t

  ! ── Session state (WORM-sealed) ──────────────────────────────────────────
  TYPE :: session_t
    TYPE(workspace_t)  :: workspace
    INTEGER(C_INT64_T) :: frame_count     = 0
    LOGICAL            :: bob_context_loaded = .FALSE.
    INTEGER(C_INT32_T) :: session_id      = 0
    LOGICAL            :: running         = .FALSE.
  END TYPE session_t

  TYPE(session_t), SAVE :: g_session

  PUBLIC :: shell_init
  PUBLIC :: shell_run
  PUBLIC :: shell_shutdown
  PUBLIC :: shell_open_file
  PUBLIC :: shell_close_file
  PUBLIC :: shell_split_panel
  PUBLIC :: shell_save_session
  PUBLIC :: shell_restore_session

CONTAINS

  ! ---------------------------------------------------------------------------
  SUBROUTINE shell_init(workspace_root)
    CHARACTER(LEN=*), INTENT(IN) :: workspace_root
    CALL runtime_init()
    g_session%workspace%root_path_id = str_intern(workspace_root)
    g_session%workspace%panel_count  = 1
    g_session%workspace%active_panel = 1
    g_session%workspace%panels(1)%active = .TRUE.
    g_session%running = .TRUE.
    g_session%frame_count = 0
    WRITE(*,'(A,A)') '[shell] init workspace: ', TRIM(workspace_root)
  END SUBROUTINE shell_init

  ! ---------------------------------------------------------------------------
  ! Main event loop: poll β†’ update β†’ render β†’ repeat
  SUBROUTINE shell_run()
    DO WHILE (g_session%running)
      g_session%frame_count = g_session%frame_count + 1
      ! 1. Poll OS events (Layer 1 platform)
      ! TODO: CALL platform_poll_events()
      ! 2. Process input (Layer 2 GUI input dispatch)
      ! TODO: CALL gui_process_input()
      ! 3. Update all active layers
      ! TODO: CALL lsp_tick()      β€” Layer 12
      ! TODO: CALL dap_tick()      β€” Layer 13
      ! TODO: CALL ext_host_tick() β€” Layer 14
      ! 4. Begin frame (Layer 2 GUI)
      ! TODO: CALL gui_begin_frame()
      ! 5. Render panels β†’ text buffers β†’ syntax highlighting
      ! TODO: CALL gui_render_panels()
      ! 6. End frame
      ! TODO: CALL gui_end_frame()
      ! 7. Auto-save session every 300 frames
      IF (MOD(g_session%frame_count, 300) == 0) CALL shell_save_session()
      ! Stub: exit after first frame for now
      g_session%running = .FALSE.
    END DO
  END SUBROUTINE shell_run

  ! ---------------------------------------------------------------------------
  SUBROUTINE shell_shutdown()
    CALL shell_save_session()
    ! Teardown in reverse order: 15 β†’ 0
    ! TODO: CALL ext_host_shutdown()  β€” Layer 14
    ! TODO: CALL dap_shutdown()       β€” Layer 13
    ! TODO: CALL lsp_shutdown()       β€” Layer 12
    ! TODO: CALL build_shutdown()     β€” Layer 11
    ! ...
    CALL runtime_teardown()
    WRITE(*,'(A,I0,A)') '[shell] shutdown after ', g_session%frame_count, ' frames'
  END SUBROUTINE shell_shutdown

  ! ---------------------------------------------------------------------------
  SUBROUTINE shell_open_file(path)
    CHARACTER(LEN=*), INTENT(IN) :: path
    INTEGER(C_INT32_T) :: fid
    IF (g_session%workspace%open_count >= MAX_OPEN_FILES) &
      CALL runtime_panic('shell_open_file: too many open files')
    fid = str_intern(path)
    g_session%workspace%open_count = g_session%workspace%open_count + 1
    g_session%workspace%open_files(g_session%workspace%open_count) = fid
    g_session%workspace%dirty = .TRUE.
    WRITE(*,'(A,A)') '[shell] opened: ', TRIM(path)
  END SUBROUTINE shell_open_file

  ! ---------------------------------------------------------------------------
  SUBROUTINE shell_close_file(idx)
    INTEGER, INTENT(IN) :: idx
    INTEGER :: i
    IF (idx < 1 .OR. idx > g_session%workspace%open_count) RETURN
    DO i = idx, g_session%workspace%open_count - 1
      g_session%workspace%open_files(i) = g_session%workspace%open_files(i+1)
    END DO
    g_session%workspace%open_count = g_session%workspace%open_count - 1
    g_session%workspace%dirty = .TRUE.
  END SUBROUTINE shell_close_file

  ! ---------------------------------------------------------------------------
  SUBROUTINE shell_split_panel(direction)
    CHARACTER(LEN=*), INTENT(IN) :: direction
    INTEGER :: n
    n = g_session%workspace%panel_count
    IF (n >= MAX_PANELS) RETURN
    g_session%workspace%panel_count = n + 1
    g_session%workspace%panels(n+1)%active = .TRUE.
    IF (direction == 'v') THEN
      g_session%workspace%panels(n)%w   = g_session%workspace%panels(n)%w * 0.5
      g_session%workspace%panels(n+1)%x = g_session%workspace%panels(n)%x + g_session%workspace%panels(n)%w
      g_session%workspace%panels(n+1)%w = g_session%workspace%panels(n)%w
    ELSE
      g_session%workspace%panels(n)%h   = g_session%workspace%panels(n)%h * 0.5
      g_session%workspace%panels(n+1)%y = g_session%workspace%panels(n)%y + g_session%workspace%panels(n)%h
      g_session%workspace%panels(n+1)%h = g_session%workspace%panels(n)%h
    END IF
    g_session%workspace%dirty = .TRUE.
  END SUBROUTINE shell_split_panel

  ! ---------------------------------------------------------------------------
  ! Session save: serialize workspace to WORM-sealed JSON
  SUBROUTINE shell_save_session()
    IF (.NOT. g_session%workspace%dirty) RETURN
    ! TODO: serialize workspace_t β†’ JSON
    ! TODO: CALL bifrost_worm_append(session_json)  β€” Layer 0 WORM
    g_session%workspace%dirty = .FALSE.
    WRITE(*,'(A,I0)') '[shell] session saved at frame ', g_session%frame_count
  END SUBROUTINE shell_save_session

  ! ---------------------------------------------------------------------------
  SUBROUTINE shell_restore_session(session_path)
    CHARACTER(LEN=*), INTENT(IN) :: session_path
    ! TODO: read WORM-sealed session file
    ! TODO: deserialize β†’ workspace_t
    ! TODO: re-open all files (Layer 3 buffer restore)
    ! TODO: reconnect BOB context (Layer 14 ext_host_connect_bob)
    g_session%bob_context_loaded = .TRUE.
    WRITE(*,'(A,A)') '[shell] restored session: ', TRIM(session_path)
  END SUBROUTINE shell_restore_session

END MODULE sovereign_shell