fortrangoingonforty/fortsh / 58b54e1

Browse files

extended test suite passing, last few issues

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
58b54e146e1539302623dc3550b20328d2f0bd58
Parents
a879463
Tree
57ecf18

2 changed files

StatusFile+-
M src/execution/better_errors.f90 43 10
M src/parsing/parser.f90 18 12
src/execution/better_errors.f90modified
@@ -4,7 +4,8 @@
44
 ! ==============================================================================
55
 module better_errors
66
   use iso_fortran_env, only: error_unit
7
-  use system_interface, only: get_environment_var
7
+  use system_interface, only: get_environment_var, c_isatty
8
+  use iso_c_binding, only: c_int
89
   implicit none
910
   private
1011
 
@@ -31,19 +32,34 @@ contains
3132
     character(len=*), intent(in) :: command
3233
     character(len=:), allocatable :: suggestions(:)
3334
     integer :: num_suggestions, i
35
+    character(len=10) :: shell_name
3436
 
35
-    ! Print main error message in red
36
-    write(error_unit, '(a,a,a,a)') &
37
-      color_code(COLOR_RED), &
38
-      "fortsh: Unknown command '", trim(command), "'"
39
-    write(error_unit, '(a)') color_code(COLOR_RESET)
37
+    ! Use "sh" for POSIX compliance in non-interactive mode
38
+    if (stderr_is_tty()) then
39
+      shell_name = "fortsh"
40
+    else
41
+      shell_name = "sh"
42
+    end if
43
+
44
+    ! Print main error message in red (POSIX format)
45
+    write(error_unit, '(a,a,a,a,a)') &
46
+      trim(color_code(COLOR_RED)), &
47
+      trim(shell_name), ": line 1: ", trim(command), ": command not found"
48
+
49
+    ! Only write color reset if using colors
50
+    if (stderr_is_tty()) then
51
+      write(error_unit, '(a)') trim(color_code(COLOR_RESET))
52
+    end if
53
+
54
+    ! Only show suggestions if stderr is a TTY (interactive mode)
55
+    if (.not. stderr_is_tty()) return
4056
 
4157
     ! Try to find similar commands
4258
     call suggest_similar_commands(command, suggestions, num_suggestions)
4359
 
4460
     if (num_suggestions > 0) then
4561
       ! Print suggestions
46
-      write(error_unit, '(a)', advance='no') color_code(COLOR_CYAN)
62
+      write(error_unit, '(a)', advance='no') trim(color_code(COLOR_CYAN))
4763
       write(error_unit, '(a)', advance='no') "Did you mean"
4864
 
4965
       if (num_suggestions == 1) then
@@ -54,12 +70,12 @@ contains
5470
         write(error_unit, '(a)') ":"
5571
         do i = 1, num_suggestions
5672
           write(error_unit, '(a)', advance='no') "  "
57
-          write(error_unit, '(a)', advance='no') color_code(COLOR_GREEN)
73
+          write(error_unit, '(a)', advance='no') trim(color_code(COLOR_GREEN))
5874
           write(error_unit, '(a)', advance='no') trim(suggestions(i))
59
-          write(error_unit, '(a)') color_code(COLOR_CYAN)
75
+          write(error_unit, '(a)') trim(color_code(COLOR_CYAN))
6076
         end do
6177
       end if
62
-      write(error_unit, '(a)') color_code(COLOR_RESET)
78
+      write(error_unit, '(a)') trim(color_code(COLOR_RESET))
6379
     end if
6480
 
6581
     ! Cleanup
@@ -279,11 +295,28 @@ contains
279295
     deallocate(matrix)
280296
   end function
281297
 
298
+  ! Check if stderr is a TTY (terminal)
299
+  function stderr_is_tty() result(is_tty)
300
+    logical :: is_tty
301
+    integer(c_int) :: result
302
+
303
+    ! error_unit is typically 0 or 2 depending on implementation
304
+    ! Standard error is file descriptor 2
305
+    result = c_isatty(int(2, c_int))
306
+    is_tty = (result /= 0)
307
+  end function
308
+
282309
   ! Generate ANSI color code
283310
   function color_code(color) result(code)
284311
     integer, intent(in) :: color
285312
     character(len=16) :: code
286313
 
314
+    ! Only use colors if stderr is a TTY
315
+    if (.not. stderr_is_tty()) then
316
+      code = ''
317
+      return
318
+    end if
319
+
287320
     if (color == COLOR_RESET) then
288321
       code = char(27) // '[0m'
289322
     else
src/parsing/parser.f90modified
@@ -1362,20 +1362,26 @@ contains
13621362
             if (.not. (is_alnum(working_token(i:i)) .or. working_token(i:i) == '_')) exit
13631363
             i = i + 1
13641364
           end do
1365
-          
1365
+
13661366
           var_name = working_token(var_start:i-1)
1367
-          
1368
-          ! Check shell variables first
1369
-          var_value = get_shell_variable(shell, trim(var_name))
1370
-          if (len_trim(var_value) > 0) then
1371
-            result(j:j+len_trim(var_value)-1) = trim(var_value)
1372
-            j = j + len_trim(var_value)
1367
+
1368
+          ! If no valid variable name was found, treat $ as literal
1369
+          if (len_trim(var_name) == 0) then
1370
+            result(j:j) = '$'
1371
+            j = j + 1
13731372
           else
1374
-            ! Fall back to environment variables
1375
-            var_value = get_environment_var(trim(var_name))
1376
-            if (allocated(var_value) .and. len(var_value) > 0) then
1377
-              result(j:j+len(var_value)-1) = var_value
1378
-              j = j + len(var_value)
1373
+            ! Check shell variables first
1374
+            var_value = get_shell_variable(shell, trim(var_name))
1375
+            if (len_trim(var_value) > 0) then
1376
+              result(j:j+len_trim(var_value)-1) = trim(var_value)
1377
+              j = j + len_trim(var_value)
1378
+            else
1379
+              ! Fall back to environment variables
1380
+              var_value = get_environment_var(trim(var_name))
1381
+              if (allocated(var_value) .and. len(var_value) > 0) then
1382
+                result(j:j+len(var_value)-1) = var_value
1383
+                j = j + len(var_value)
1384
+              end if
13791385
             end if
13801386
           end if
13811387
         end if