home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / progmisc / euphor10.zip / ED.EX < prev    next >
Text File  |  1993-06-25  |  31KB  |  1,276 lines

  1.     ----------------------------------------------------------
  2.     -- This Euphoria Editor was developed by                --
  3.     -- Rapid Deployment Software.                           --
  4.     -- Permission is freely granted to anyone to modify     --
  5.     -- and/or redistribute this editor (ed.ex, syncolor.e). --
  6.     -- You may even sell it as it is, or with your          --
  7.     -- modifications. Remember however, that while the      --
  8.     -- Public Domain Edition of ex.exe may also be          --
  9.     -- copied and distributed freely, the Complete Edition  --
  10.     -- of ex.exe, and the manual must be purchased          --
  11.     -- from Rapid Deployment Software. Type 'ex' to find    --
  12.     -- out which version you have.                          --                                      --
  13.     ----------------------------------------------------------
  14.  
  15. without type_check -- makes it a bit faster
  16.  
  17. include graphics.e
  18.  
  19. constant TRUE = 1,
  20.      FALSE = 0
  21.  
  22. -- i/o devices
  23. constant KEYB = 0
  24. global constant SCREEN = 1
  25.  
  26. -- screen dimensions
  27. constant INIT_SCREEN_LENGTH = 25, -- 25, 28, 43, 50
  28.      SCREEN_WIDTH = 80
  29.  
  30. -- colors
  31. constant TOP_LINE_TEXT_COLOR = 0,
  32.      TOP_LINE_BACK_COLOR = 14,
  33.      BACKGROUND_COLOR = 7
  34.  
  35. -- colors needed by syncolor.e:
  36. global constant NORMAL_COLOR = 8,
  37.         COMMENT_COLOR = 4,
  38.         KEYWORD_COLOR = 1,
  39.         BUILTIN_COLOR = 5,
  40.         STRING_COLOR = 6
  41. global constant bracket_color = {NORMAL_COLOR, 0, 14, 2, 15, 3, 9}
  42.  
  43. -- cursor style
  44. constant ED_CURSOR = UNDERLINE_CURSOR
  45.  
  46. constant TAB_WIDTH = 8
  47.  
  48. global constant BLANK_LINE = repeat('\t', SCREEN_WIDTH/TAB_WIDTH)
  49.  
  50. -- special input characters
  51. constant ESCAPE = 27,
  52.      CR = 13,
  53.      BS = 8,
  54.      HOME = 327,
  55.      PAGE_UP = 329,
  56.      END = 335,
  57.      PAGE_DOWN = 337,
  58.      INSERT = 338,
  59.      DELETE = 339,
  60.      CONTROL_DELETE = 403,
  61.      ARROW_LEFT = 331,
  62.      ARROW_RIGHT = 333,
  63.      ARROW_UP = 328,
  64.      ARROW_DOWN = 336
  65.  
  66. constant CONTROL_CHARS = {ESCAPE, BS, DELETE, PAGE_UP, PAGE_DOWN,
  67.               INSERT, CONTROL_DELETE,
  68.               ARROW_LEFT, ARROW_RIGHT, ARROW_UP, ARROW_DOWN,
  69.               HOME, END}
  70.  
  71. sequence buffer -- In-memory buffer where the file is manipulated.
  72. -- This is a sequence where each element is a sequence
  73. -- containing one line of text.
  74. -- Each line of text, except possibly the last one, ends with '\n'
  75.  
  76. type natural(integer x)
  77.     return x >= 0
  78. end type
  79.  
  80. type positive_int(integer x)
  81.     return x >= 1
  82. end type
  83.  
  84. positive_int screen_length
  85. screen_length = INIT_SCREEN_LENGTH
  86.  
  87. type screen_line(integer x)
  88. -- a valid line on the screen
  89.     return x >= 1 and x <= screen_length
  90. end type
  91.  
  92. type screen_col(integer x)
  93. -- a valid column on the screen
  94.     return x >= 1 and x <= SCREEN_WIDTH
  95. end type
  96.  
  97. type buffer_line(integer x)
  98. -- a valid buffer line
  99.     return x >= 1 and x <= length(buffer)
  100. end type
  101.  
  102. type char(integer x)
  103. -- a character
  104.     return x >= 0 and x <= 511
  105. end type
  106.  
  107. type extended_char(integer x)
  108.     return char(x) or x = -1
  109. end type
  110.  
  111. type boolean(integer x)
  112.     return x = TRUE or x = FALSE
  113. end type
  114.  
  115. type file_number(integer x)
  116.     return x >= -1
  117. end type
  118.  
  119. -- editing options -----------------------------------------------------------
  120. boolean multi_color   -- use colors for keywords etc.
  121. multi_color   = TRUE  -- set to FALSE if you don't want colors
  122. boolean auto_complete -- auto-completion of Euphoria statements in .e/.ex files
  123. auto_complete = TRUE  -- set to FALSE if you don't want it
  124. ------------------------------------------------------------------------------
  125.  
  126. sequence file_name   -- name of the file that we are editing
  127.  
  128. -- These are the critical variables that all editing operations
  129. -- must update:
  130. buffer_line  b_line  -- current line in buffer
  131. positive_int b_col   -- current character within line in buffer
  132. screen_line  s_line  -- line on screen corresponding to b_line
  133. screen_col   s_col   -- column on screen corresponding to b_col
  134.  
  135. boolean stop         -- indicates when to quit the editor
  136.  
  137. sequence kill_buffer -- kill buffer of deleted lines or characters
  138. kill_buffer = {}
  139.  
  140. boolean adding_to_kill -- TRUE if still accumulating deleted lines/chars
  141.  
  142. boolean dot_e        -- TRUE if this is a .e/.ex file
  143. boolean modified     -- TRUE if file has been modified
  144.  
  145. boolean top_line_set
  146.  
  147. natural start_line, start_col
  148.  
  149. sequence error_message
  150.  
  151. sequence config -- video configuration
  152.  
  153. procedure delay(atom n)
  154. -- an n second pause while a message is on the screen
  155.     atom t
  156.  
  157.     t = time()
  158.     while time() < t + n do
  159.     end while
  160. end procedure
  161.  
  162. function tab(positive_int pos)
  163. -- compute equivalent number of spaces for tab
  164.     return(floor((pos - 1) / TAB_WIDTH) + 1) * TAB_WIDTH + 1
  165. end function
  166.  
  167. -- color display of lines
  168. include syncolor.e
  169.  
  170. procedure DisplayLine(buffer_line line, screen_line sline, boolean all_clear)
  171. -- display a buffer line on a given line on the screen
  172. -- all_clear indicates that trailing whitespace is not necessary
  173.     sequence this_line
  174.     natural last
  175.  
  176.     this_line = buffer[line]
  177.     last = length(this_line)
  178.     if this_line[last] = '\n' then
  179.     last = last - 1
  180.     end if
  181.     position(sline, 1)
  182.     if multi_color then
  183.     -- color display
  184.     DisplayColorLine(this_line[1..last], all_clear)
  185.     else
  186.     -- monochrome display
  187.     if all_clear then
  188.         puts(SCREEN, this_line[1..last])
  189.     else
  190.         puts(SCREEN, this_line[1..last] & BLANK_LINE)
  191.     end if
  192.     end if
  193. end procedure
  194.  
  195. procedure DisplayScreen(positive_int bline, screen_line sline)
  196. -- print a series of buffer lines, starting at sline on screen
  197. -- and continue until the end of screen, or end of buffer
  198.     boolean all_clear
  199.  
  200.     if sline = 1 then
  201.     clear_screen() -- faster
  202.     all_clear = TRUE
  203.     else
  204.     all_clear = FALSE
  205.     end if
  206.     for b = bline to length(buffer) do
  207.     DisplayLine(b, sline, all_clear)
  208.     if sline = screen_length then
  209.         return
  210.     else
  211.         sline = sline + 1
  212.     end if
  213.     end for
  214.     -- blank any remaining screen lines after end of file
  215.     if not all_clear then
  216.     for s = sline to screen_length do
  217.         position(s, 1)
  218.         puts(SCREEN, BLANK_LINE)
  219.     end for
  220.     end if
  221. end procedure
  222.  
  223.  
  224. procedure read_file(file_number file_no)
  225. -- read the entire file into buffer variable
  226.  
  227.     object line
  228.  
  229.     buffer = {}
  230.  
  231.     -- read and immediately display the first screenful
  232.     for i = 1 to screen_length do
  233.     line = gets(file_no)
  234.     if atom(line) then
  235.         exit
  236.     end if
  237.     buffer = append(buffer, line)
  238.     end for
  239.     DisplayScreen(1, 1)
  240.  
  241.     -- read the rest
  242.     while TRUE do
  243.     line = gets(file_no)
  244.     if atom(line) then
  245.         return
  246.     end if
  247.     buffer = append(buffer, line)
  248.     end while
  249. end procedure
  250.  
  251. procedure blank_top_line()
  252.     position(1, 1)
  253.     puts(SCREEN, BLANK_LINE)
  254.     position(1, 1)
  255. end procedure
  256.  
  257. procedure reverse_video()
  258. -- start inverse video
  259.     text_color(TOP_LINE_TEXT_COLOR)
  260.     bk_color(TOP_LINE_BACK_COLOR)
  261. end procedure
  262.  
  263. procedure normal_video()
  264. -- end inverse video
  265.     text_color(NORMAL_COLOR)
  266.     bk_color(BACKGROUND_COLOR)
  267. end procedure
  268.  
  269. procedure set_top_line(sequence message)
  270.     -- set up message on top line
  271.     reverse_video()
  272.     blank_top_line()
  273.     puts(SCREEN, message)
  274.     top_line_set = TRUE
  275. end procedure
  276.  
  277. procedure clear_top_line()
  278.     -- restore top line
  279.     if length(buffer) = 0 then
  280.     blank_top_line()
  281.     elsif top_line_set then
  282.     DisplayLine(b_line - s_line + 1, 1, FALSE)
  283.     position(s_line, s_col)
  284.     end if
  285.     top_line_set = FALSE
  286. end procedure
  287.  
  288. procedure save_file(sequence file_name)
  289. -- write buffer back into the disk file
  290.  
  291.     file_number file_no
  292.  
  293.     set_top_line("")
  294.     printf(SCREEN, "saving %s ...          ", {file_name})
  295.     file_no = open(file_name, "w")
  296.     if file_no = -1 then
  297.     printf(SCREEN, "Can't save %s !!!\n", file_name)
  298.     return
  299.     end if
  300.     for i = 1 to length(buffer) do
  301.     puts(file_no, buffer[i])
  302.     end for
  303.     close(file_no)
  304. end procedure
  305.  
  306. procedure arrow_right()
  307. -- action for right arrow key
  308.  
  309.     positive_int temp_col
  310.  
  311.     if s_col < SCREEN_WIDTH and b_col < length(buffer[b_line]) then
  312.     if buffer[b_line][b_col] = '\t' then
  313.         temp_col = tab(s_col)
  314.     else
  315.         temp_col = s_col + 1
  316.     end if
  317.     if temp_col > SCREEN_WIDTH then
  318.         return
  319.     end if
  320.     s_col = temp_col
  321.     b_col = b_col + 1
  322.     end if
  323. end procedure
  324.  
  325. procedure arrow_left()
  326. -- action for left arrow key
  327.  
  328.     positive_int old_b_col
  329.  
  330.     old_b_col = b_col
  331.     b_col = 1
  332.     s_col = 1
  333.     for i = 1 to old_b_col - 2 do
  334.     arrow_right()
  335.     end for
  336. end procedure
  337.  
  338. procedure arrow_up()
  339. -- action for up arrow key
  340.  
  341.     b_col = 1
  342.     s_col = 1
  343.     if b_line > 1 then
  344.     b_line = b_line - 1
  345.     if s_line > 1 then
  346.         s_line = s_line - 1
  347.         if s_line = 1 then
  348.         clear_top_line()
  349.         end if
  350.     else
  351.         -- move all lines down, display new line at top
  352.         scroll(-1)
  353.         DisplayLine(b_line, 1, TRUE)
  354.         position(1, 1)
  355.         s_line = 1
  356.     end if
  357.     end if
  358. end procedure
  359.  
  360. procedure arrow_down()
  361. -- action for down arrow key
  362.  
  363.     b_col = 1
  364.     s_col = 1
  365.     if b_line < length(buffer) then
  366.     b_line = b_line + 1
  367.     if s_line < screen_length then
  368.         s_line = s_line + 1
  369.     else
  370.         -- move all lines up, display new line at bottom
  371.         scroll(+1)
  372.         DisplayLine(b_line, screen_length, TRUE)
  373.     end if
  374.     end if
  375. end procedure
  376.  
  377. function numeric(sequence string)
  378. -- convert digit string to a number
  379.     natural n
  380.     positive_int i
  381.  
  382.     n = 0
  383.     i = 1
  384.     while string[i] >= '0' and string[i] <= '9' do
  385.     n = n * 10 + string[i] - '0'
  386.     i = i + 1
  387.     end while
  388.     return n
  389. end function
  390.  
  391. procedure goto_line(integer new_line, integer new_col)
  392. -- move to a specified line and column
  393. -- refresh screen if line is 0
  394.     integer new_s_line
  395.     boolean refresh
  396.  
  397.     if length(buffer) = 0 then
  398.     return
  399.     end if
  400.     if new_line = 0 then
  401.     new_line = b_line
  402.     refresh = TRUE
  403.     else
  404.     refresh = FALSE
  405.     end if
  406.     if new_line < 1 then
  407.     new_line = 1
  408.     elsif new_line > length(buffer) then
  409.     new_line = length(buffer)
  410.     end if
  411.     new_s_line = new_line - b_line + s_line
  412.     b_line = new_line
  413.     if not refresh and screen_line(new_s_line) then
  414.     -- new line is on the screen
  415.     s_line = new_s_line
  416.     else
  417.     -- new line is off the screen, or refreshing
  418.     position(1, 1)
  419.     s_line = floor(screen_length/2)
  420.     if s_line > b_line or length(buffer) < screen_length then
  421.         s_line = b_line
  422.     elsif b_line > length(buffer) - screen_length + s_line then
  423.         s_line = screen_length - (length(buffer) - b_line)
  424.     end if
  425.     DisplayScreen(b_line - s_line + 1, 1)
  426.     end if
  427.     b_col = 1
  428.     s_col = 1
  429.     position(s_line, s_col)
  430.     for i = 1 to new_col-1 do
  431.     arrow_right()
  432.     end for
  433. end procedure
  434.  
  435. procedure page_down()
  436. -- action for page-down key
  437.     buffer_line prev_b_line
  438.  
  439.     if length(buffer) <= screen_length then
  440.     return
  441.     end if
  442.     prev_b_line = b_line
  443.     b_col = 1
  444.     s_col = 1
  445.     if b_line + screen_length + screen_length - s_line <= length(buffer) then
  446.     b_line = b_line + screen_length
  447.     else
  448.     b_line = length(buffer) - (screen_length - s_line)
  449.     end if
  450.     if b_line != prev_b_line then
  451.     DisplayScreen(b_line - s_line + 1, 1)
  452.     end if
  453. end procedure
  454.  
  455. procedure page_up()
  456. -- action for page-up key
  457.     buffer_line prev_b_line
  458.  
  459.     if length(buffer) <= screen_length then
  460.     return
  461.     end if
  462.     prev_b_line = b_line
  463.     b_col = 1
  464.     s_col = 1
  465.     if b_line - screen_length >= s_line then
  466.     b_line = b_line - screen_length
  467.     else
  468.     b_line = s_line
  469.     end if
  470.     if b_line != prev_b_line then
  471.     DisplayScreen(b_line - s_line + 1, 1)
  472.     end if
  473. end procedure
  474.  
  475. procedure new_screen_length()
  476. -- set new number of lines on screen
  477.     natural nlines
  478.  
  479.     set_top_line("")
  480.     puts(SCREEN, "How many lines on screen? (25, 28, 43, 50) ")
  481.     nlines = numeric(gets(KEYB))
  482.     if nlines then
  483.     screen_length = text_rows(nlines)
  484.     if screen_length != nlines then
  485.         sound(500)
  486.     end if
  487.     normal_video()
  488.     if length(buffer) > 0 then
  489.         goto_line(0, b_col) -- refresh
  490.     end if
  491.     if screen_length != nlines then
  492.         sound(0)
  493.     end if
  494.     end if
  495. end procedure
  496.  
  497. -- searching/replacing variables
  498. boolean searching, replacing
  499. searching = FALSE
  500. replacing = FALSE
  501.  
  502. sequence prev_string
  503. prev_string = ""
  504. sequence replace_string -- new string to replace with
  505.  
  506. procedure replace(sequence old_string)
  507. -- replace old string by new
  508. -- we are currently positioned at the start of old string
  509.     sequence line
  510.  
  511.     modified = TRUE
  512.     line = buffer[b_line]
  513.     line = line[1..b_col-1] & replace_string & line[b_col+length(old_string)..
  514.                         length(line)]
  515.     buffer[b_line] = line
  516.     DisplayLine(b_line, s_line, FALSE)
  517. end procedure
  518.  
  519. function search(boolean continue)
  520. -- find a string from here to the end of the file
  521. -- return TRUE if string is found
  522.     natural col
  523.     sequence old_string
  524.  
  525.     if length(buffer) = 0 then
  526.     puts(SCREEN, "buffer empty")
  527.     return FALSE
  528.     end if
  529.     set_top_line("")
  530.     if length(prev_string) = 0 then
  531.     puts(SCREEN, "searching for:")
  532.     else
  533.     printf(SCREEN, "searching for \"%s\":", {prev_string})
  534.     end if
  535.     if continue then
  536.     old_string = ""
  537.     else
  538.     old_string = gets(KEYB)
  539.     old_string = old_string[1..length(old_string)-1]
  540.     if replacing then
  541.         set_top_line("")
  542.         puts(SCREEN, "replace with:")
  543.         replace_string = gets(KEYB)
  544.         replace_string = replace_string[1..length(replace_string)-1]
  545.     end if
  546.     end if
  547.  
  548.     normal_video()
  549.     if length(old_string) = 0 then
  550.     old_string = prev_string
  551.     end if
  552.     if length(old_string) = 0 then
  553.     return FALSE
  554.     end if
  555.     prev_string = old_string
  556.     col = match(old_string, buffer[b_line][b_col+1..length(buffer[b_line])])
  557.     if col and s_col < SCREEN_WIDTH then
  558.     -- found it on this line after current position
  559.     for i = 1 to col do
  560.         arrow_right()
  561.     end for
  562.     if replacing then
  563.         replace(old_string)
  564.     end if
  565.     return TRUE
  566.     else
  567.     -- check lines following this one
  568.     for b = b_line+1 to length(buffer) do
  569.         col = match(old_string, buffer[b])
  570.         if col then
  571.         goto_line(b, 1)
  572.         for i = 1 to col - 1 do
  573.            arrow_right()
  574.         end for
  575.         if replacing and s_col < SCREEN_WIDTH then
  576.             replace(old_string)
  577.         end if
  578.         set_top_line("")
  579.         printf(SCREEN, "searching for \"%s\":", {prev_string})
  580.         return TRUE
  581.         end if
  582.     end for
  583.     set_top_line("")
  584.     printf(SCREEN, "\"%s\" not found", {old_string})
  585.     end if
  586.     return FALSE
  587. end function
  588.  
  589. procedure show_message()
  590. -- display error message from ex.err
  591.     if length(error_message) > 0 then
  592.     set_top_line(error_message)
  593.     normal_video()
  594.     if start_line = 1 then
  595.         delay(3)
  596.         clear_top_line()
  597.     end if
  598.     end if
  599.     position(s_line, s_col)
  600. end procedure
  601.  
  602. function get_err_line()
  603. -- try to get file name & line number from ex.err
  604. -- returns file_name, sets start_line, start_col, error_message
  605.  
  606.     file_number err_file
  607.     sequence file_name
  608.     sequence err_lines
  609.     object temp_line
  610.     natural colon_pos
  611.  
  612.     err_file = open("ex.err", "r")
  613.     if err_file = -1 then
  614.     error_message = ""
  615.     else
  616.     -- read the top of the ex.err error message file
  617.     err_lines = {}
  618.     while length(err_lines) < 5 do
  619.         temp_line = gets(err_file)
  620.         if atom(temp_line) then
  621.         exit
  622.         end if
  623.         err_lines = append(err_lines, temp_line)
  624.     end while
  625.     close(err_file)
  626.     -- look for file name, line, column and error message
  627.     if length(err_lines) > 0 then
  628.         if sequence(err_lines[1]) then
  629.         colon_pos = match(".e", err_lines[1])
  630.         if colon_pos then
  631.             if err_lines[1][colon_pos+2] = 'x' then
  632.             colon_pos = colon_pos + 1
  633.             end if
  634.             file_name = err_lines[1][1..colon_pos+1]
  635.             start_line = numeric(err_lines[1][colon_pos+3..
  636.                               length(err_lines[1])])
  637.             error_message = err_lines[2]
  638.             if length(err_lines) > 3 then
  639.             start_col = find('^', err_lines[length(err_lines)-1])
  640.             end if
  641.             return file_name
  642.         end if
  643.         end if
  644.     end if
  645.     end if
  646.     return ""
  647. end function
  648.  
  649. procedure shell(sequence command, boolean wait)
  650. -- run a DOS command
  651.     bk_color(0)
  652.     text_color(7)
  653.     clear_screen()
  654.     system(command, wait)
  655.     normal_video()
  656.     while get_key() != -1 do
  657.     end while
  658. end procedure
  659.  
  660. procedure first_bold(sequence string)
  661. -- highlight first char
  662.     text_color(TOP_LINE_TEXT_COLOR)
  663.     puts(SCREEN, string[1])
  664.     text_color(TOP_LINE_TEXT_COLOR + 8)
  665.     puts(SCREEN, string[2..length(string)])
  666. end procedure
  667.  
  668. procedure get_escape(boolean help)
  669. -- process escape command
  670.     sequence command, dos_command, answer
  671.     natural line
  672.  
  673.     cursor(ED_CURSOR)
  674.  
  675.     set_top_line("")
  676.     if help then
  677.     command = "h"
  678.     else
  679.     first_bold("help  ")
  680.     first_bold("quit  ")
  681.     first_bold("save  ")
  682.     first_bold("write  ")
  683.     if dot_e then
  684.         first_bold("ex  ")
  685.     end if
  686.     first_bold("dos  ")
  687.     first_bold("new  ")
  688.     first_bold("find  ")
  689.     first_bold("replace  ")
  690.     first_bold("lines  ")
  691.     text_color(TOP_LINE_TEXT_COLOR)
  692.     puts(SCREEN, "<ddd>  <cr>: ")
  693.     command = gets(KEYB)
  694.     if length(command) = 0 then
  695.         command = " "
  696.     end if
  697.     end if
  698.  
  699.     if command[1] = 'f' then
  700.     replacing = FALSE
  701.     searching = search(FALSE)
  702.  
  703.     elsif command[1] = 'r' then
  704.     replacing = TRUE
  705.     searching = search(FALSE)
  706.  
  707.     elsif command[1] = 'q' then
  708.     if modified then
  709.         set_top_line("quit without saving changes? ")
  710.         if match("y", gets(KEYB)) then
  711.         file_name = ""
  712.         stop = TRUE
  713.         end if
  714.     else
  715.         file_name = ""
  716.         stop = TRUE
  717.     end if
  718.  
  719.     elsif command[1] = 'n' then
  720.     stop = TRUE
  721.     if modified then
  722.         set_top_line("")
  723.         printf(SCREEN, "save changes to %s? ", {file_name})
  724.         if match("y", gets(KEYB)) then
  725.         save_file(file_name)
  726.         end if
  727.     end if
  728.     blank_top_line()
  729.     puts(SCREEN, "new file name? ")
  730.     file_name = gets(KEYB)
  731.     file_name = file_name[1..length(file_name)-1] -- drop the \n
  732.  
  733.     elsif command[1] = 'w' then
  734.     save_file(file_name)
  735.     modified = FALSE
  736.  
  737.     elsif command[1] = 's' then
  738.     save_file(file_name)
  739.     file_name = ""
  740.     stop = TRUE
  741.  
  742.     elsif command[1] = 'e' and dot_e then
  743.     if modified then
  744.         save_file(file_name)
  745.         modified = FALSE
  746.     end if
  747.     -- execute the current file & return
  748.     system("del ex.err > NUL", 0)
  749.     shell("ex " & file_name, TRUE)
  750.     goto_line(0, b_col)
  751.     if compare(file_name, get_err_line()) = 0 then
  752.         goto_line(start_line, start_col)
  753.         show_message()
  754.     end if
  755.  
  756.     elsif command[1] = 'd' then
  757.     set_top_line("")
  758.     puts(SCREEN, "DOS command? ")
  759.     dos_command = gets(KEYB)
  760.     dos_command = dos_command[1..length(dos_command)-1]
  761.     shell(dos_command, TRUE)
  762.     goto_line(0, b_col) -- refresh screen
  763.  
  764.     elsif command[1] = 'h' then
  765.     set_top_line("")
  766.     dos_command = getenv("EUDIR")
  767.     if atom(dos_command) then
  768.         dos_command = "ed C:\\EUPHORIA\\DOC"
  769.     else
  770.         dos_command = "ed " & dos_command & "\\DOC"
  771.     end if
  772.     if help then
  773.         puts(SCREEN,
  774.         "That key does nothing - do you want to view the help text? ")
  775.         answer = gets(KEYB)
  776.         if answer[1] != 'n' and answer[1] != 'N' then
  777.         answer = "e"
  778.         end if
  779.     else
  780.         puts(SCREEN,
  781.          "Help text for ed, or for Euphoria? (e or E): ")
  782.         answer = gets(KEYB)
  783.     end if
  784.     if answer[1] = 'E' then
  785.         shell(dos_command & "\\MINIMAN.DOC", FALSE)
  786.     elsif answer[1] = 'e' then
  787.         shell(dos_command & "\\ED.DOC", FALSE)
  788.     else
  789.         normal_video()
  790.     end if
  791.     goto_line(0, b_col)
  792.  
  793.     elsif command[1] = 'l' then
  794.     new_screen_length()
  795.  
  796.     elsif command[1] >= '0' and command[1] <= '9' then
  797.     line = numeric(command)
  798.     normal_video()
  799.     goto_line(line, 1)
  800.     if not buffer_line(line) then
  801.         set_top_line("")
  802.         printf(SCREEN, "lines are 1..%d", length(buffer))
  803.         if s_line = 1 then
  804.         delay(3)
  805.         end if
  806.     end if
  807.  
  808.     else
  809.     set_top_line("")
  810.     if length(buffer) = 0 then
  811.         puts(SCREEN, "empty buffer")
  812.         delay(3)
  813.     else
  814.         printf(SCREEN, "%s line %d of %d, column %d of %d, ",
  815.                {file_name, b_line, length(buffer), s_col,
  816.             SCREEN_WIDTH})
  817.         if modified then
  818.         puts(SCREEN, "modified")
  819.         else
  820.         puts(SCREEN, "not modified")
  821.         end if
  822.         if s_line = 1 then
  823.         delay(3)
  824.         end if
  825.     end if
  826.     end if
  827.  
  828.     normal_video()
  829.     if s_line = 1 or length(buffer) = 0 then
  830.     clear_top_line()
  831.     end if
  832. end procedure
  833.  
  834.  
  835. procedure insert(char key)
  836. -- insert a character into the current line at the current position
  837.  
  838.     sequence tail
  839.     positive_int new_col, b_col_save
  840.     screen_col s_col_save
  841.  
  842.     modified = TRUE
  843.     tail = buffer[b_line][b_col..length(buffer[b_line])]
  844.     if key = CR or key = '\n' then
  845.     -- truncate this line and create a new line using tail
  846.     buffer[b_line] = buffer[b_line][1..b_col-1] & '\n'
  847.     buffer = append(buffer[1..b_line], tail) &
  848.             buffer[b_line+1..length(buffer)]
  849.     if s_line = screen_length then
  850.         s_col_save = s_col
  851.         b_col_save = b_col
  852.         arrow_down()
  853.         arrow_up()
  854.         s_col = s_col_save
  855.         b_col = b_col_save
  856.         position(s_line, s_col)
  857.     end if
  858.     DisplayScreen(b_line, s_line)
  859.     b_line = b_line + 1
  860.     s_line = s_line + 1
  861.     s_col = 1
  862.     b_col = 1
  863.     else
  864.     if key = '\t' then
  865.         new_col = tab(s_col)
  866.     else
  867.         new_col = s_col + 1
  868.     end if
  869.     if new_col > SCREEN_WIDTH then
  870.         return
  871.     else
  872.         s_col = new_col
  873.     end if
  874.     buffer[b_line] = buffer[b_line][1..b_col-1] & key & tail
  875.     DisplayLine(b_line, s_line, TRUE)
  876.     b_col = b_col + 1
  877.     end if
  878.     position(s_line, s_col)
  879. end procedure
  880.  
  881. procedure insert_string(sequence text)
  882. -- insert a bunch of characters at the current position
  883.     natural save_line, save_col
  884.     
  885.     save_line = b_line
  886.     save_col = b_col
  887.     for i = 1 to length(text) do
  888.     if text[i] = CR or text[i] = '\n' then
  889.         insert(text[i])
  890.     else
  891.         buffer[b_line] = buffer[b_line][1..b_col-1] & text[i] &
  892.                  buffer[b_line][b_col..length(buffer[b_line])]                
  893.         b_col = b_col + 1
  894.         if i = length(text) then
  895.         DisplayLine(b_line, s_line, TRUE)
  896.         end if
  897.     end if
  898.     end for
  899.     goto_line(save_line, save_col)    
  900. end procedure
  901.  
  902. -- expandable words & corresponding text
  903. constant expand_word = {"if", "for", "while", "elsif",
  904.             "procedure", "type", "function"},
  905.  
  906.      expand_text = {" then", "=  to  by  do", " do", " then",
  907.             "()",
  908.             "()" & CR & "    return",
  909.             "()" & CR & "    return"}
  910.  
  911. procedure try_auto_complete()
  912. -- check for a keyword that can be automatically completed
  913.     sequence word, this_line, white_space
  914.     natural first_non_blank, wordnum 
  915.  
  916.     insert(' ')
  917.     if not auto_complete then
  918.     return
  919.     end if
  920.     this_line = buffer[b_line]
  921.     white_space = this_line = ' ' or this_line = '\t'
  922.     first_non_blank = find(0, white_space)
  923.     if first_non_blank > 0 and first_non_blank < b_col - 2 then
  924.     if not find(0, white_space[b_col..length(white_space)-1]) then
  925.         word = this_line[first_non_blank..b_col - 2]
  926.         wordnum = find(word, expand_word)
  927.         if wordnum > 0 then
  928.         sound(1000)
  929.         -- expandable word (only word on line)
  930.         if compare(expand_word[wordnum], "elsif") = 0 then
  931.             insert_string(expand_text[wordnum])
  932.             delay(0.07) -- or beep is too short
  933.         else
  934.             insert_string(expand_text[wordnum] & CR & 
  935.                   this_line[1..first_non_blank - 1] &
  936.                       "end " & expand_word[wordnum])
  937.         end if
  938.         sound(0)
  939.         end if
  940.     end if
  941.     end if
  942. end procedure
  943.  
  944. procedure insert_kill_buffer()
  945. -- insert the kill buffer at the current position
  946. -- kill buffer could be a sequence of lines or a sequence of characters
  947.  
  948.     if length(kill_buffer) = 0 then
  949.     return
  950.     end if
  951.     if atom(kill_buffer[1]) then
  952.     -- inserting a sequence of chars
  953.     insert_string(kill_buffer)
  954.     else
  955.     -- inserting a sequence of lines
  956.     modified = TRUE
  957.     buffer = buffer[1..b_line - 1] &
  958.          kill_buffer &
  959.          buffer[b_line..length(buffer)]
  960.     DisplayScreen(b_line, s_line)
  961.     arrow_up()
  962.     arrow_down()
  963.     end if
  964. end procedure
  965.  
  966. procedure delete_line(buffer_line dead_line)
  967. -- delete a line from the buffer and update the display if necessary
  968.  
  969.     integer x
  970.  
  971.     modified = TRUE
  972.     buffer = buffer[1..dead_line-1] & buffer[dead_line+1 .. length(buffer)]
  973.     x = dead_line - b_line + s_line
  974.     if screen_line(x) then
  975.     -- dead line is on the screen at line x
  976.     DisplayScreen(dead_line, x)
  977.     end if
  978.     if b_line = 1 then
  979.     arrow_down()
  980.     arrow_up()
  981.     else
  982.     arrow_up()
  983.     arrow_down()
  984.     end if
  985.     adding_to_kill = TRUE
  986. end procedure
  987.  
  988.  
  989. procedure delete_char()
  990. -- delete the character at the current position
  991.     char dchar
  992.     sequence head
  993.     natural save_b_col
  994.  
  995.     modified = TRUE
  996.     dchar = buffer[b_line][b_col]
  997.     head = buffer[b_line][1..b_col - 1]
  998.     if dchar = '\n' and b_line < length(buffer) then
  999.     -- join this line with the next one and delete the next one
  1000.     buffer[b_line] = head & buffer[b_line+1]
  1001.     DisplayLine(b_line, s_line, FALSE)
  1002.     save_b_col = b_col
  1003.     delete_line(b_line + 1)
  1004.     for i = 1 to save_b_col - 1 do
  1005.         arrow_right()
  1006.     end for
  1007.     else
  1008.     buffer[b_line] = head & buffer[b_line][b_col+1..length(buffer[b_line])]
  1009.     if length(buffer[b_line]) = 0 then
  1010.         delete_line(b_line)
  1011.     else
  1012.         DisplayLine(b_line, s_line, FALSE)
  1013.         if b_col > length(buffer[b_line]) then
  1014.         arrow_left()
  1015.         end if
  1016.     end if
  1017.     end if
  1018.     adding_to_kill = TRUE
  1019. end procedure
  1020.  
  1021.  
  1022. function good(extended_char key)
  1023. -- return TRUE if key should be processed
  1024.     if find(key, CONTROL_CHARS & '\t' & CR) or (key >= ' ' and key <= 127) then
  1025.     return TRUE
  1026.     else
  1027.     return FALSE
  1028.     end if
  1029. end function
  1030.  
  1031. procedure edit_file()
  1032. -- edit the file in buffer
  1033.     extended_char key
  1034.  
  1035.     position(1, 1)
  1036.     s_line = 1
  1037.     s_col = 1
  1038.     if length(buffer) > 0 then
  1039.     b_line = 1
  1040.     b_col = 1
  1041.     if start_line > 0 then
  1042.         if start_line > length(buffer) then
  1043.         start_line = length(buffer)
  1044.         end if
  1045.         goto_line(start_line, start_col)
  1046.         show_message()
  1047.     end if
  1048.     end if
  1049.     cursor(ED_CURSOR)
  1050.     stop = FALSE
  1051.     while not stop do
  1052.     key = get_key()
  1053.  
  1054.     if good(key) then
  1055.         -- normal key
  1056.  
  1057.         -- hide cursor while we update the screen
  1058.         cursor(NO_CURSOR)
  1059.  
  1060.         if length(buffer) = 0 and key != ESCAPE then
  1061.         -- empty buffer
  1062.         -- only allowed action is to insert something
  1063.         if key = INSERT or not find(key, CONTROL_CHARS) then
  1064.             -- initialize buffer
  1065.             buffer = {{'\n'}} -- one line with \n
  1066.             b_line = 1
  1067.             b_col = 1
  1068.             s_line = 1
  1069.             s_col = 1
  1070.             if key = INSERT then
  1071.             insert_kill_buffer()
  1072.             else
  1073.             insert(key)
  1074.             end if
  1075.             DisplayLine(1, 1, FALSE)
  1076.         end if
  1077.  
  1078.         elsif key = DELETE then
  1079.         if not adding_to_kill then
  1080.             kill_buffer = {buffer[b_line][b_col]}
  1081.         elsif sequence(kill_buffer[1]) then
  1082.             -- we were building up deleted lines,
  1083.             -- but now we'll switch to chars
  1084.             kill_buffer = {buffer[b_line][b_col]}
  1085.         else
  1086.             kill_buffer = append(kill_buffer, buffer[b_line][b_col])
  1087.         end if
  1088.         delete_char()
  1089.  
  1090.         elsif key = CONTROL_DELETE then
  1091.         if not adding_to_kill then
  1092.             kill_buffer = {buffer[b_line]}
  1093.         elsif atom(kill_buffer[1]) then
  1094.             -- we were building up deleted chars,
  1095.             -- but now we'll switch to lines
  1096.             kill_buffer = {buffer[b_line]}
  1097.         else
  1098.             kill_buffer = append(kill_buffer, buffer[b_line])
  1099.         end if
  1100.         delete_line(b_line)
  1101.  
  1102.         else
  1103.         if key = ARROW_DOWN then
  1104.             arrow_down()
  1105.  
  1106.         elsif key = ARROW_UP then
  1107.             arrow_up()
  1108.  
  1109.         elsif key = INSERT then
  1110.             insert_kill_buffer()
  1111.  
  1112.         elsif key = ARROW_LEFT then
  1113.             arrow_left()
  1114.  
  1115.         elsif key = ARROW_RIGHT then
  1116.             arrow_right()
  1117.  
  1118.         elsif key = ' ' then
  1119.             try_auto_complete()
  1120.  
  1121.         elsif key = BS then
  1122.             arrow_left()
  1123.             delete_char()
  1124.  
  1125.         elsif key = PAGE_DOWN then
  1126.             page_down()
  1127.  
  1128.         elsif key = PAGE_UP then
  1129.             page_up()
  1130.  
  1131.         elsif key = HOME then
  1132.             goto_line(1, 1)
  1133.  
  1134.         elsif key = END then
  1135.             goto_line(length(buffer), 1)
  1136.  
  1137.         elsif key = ESCAPE then
  1138.             -- special command
  1139.             get_escape(FALSE)
  1140.  
  1141.         elsif key = CR then
  1142.             if searching then
  1143.             searching = search(TRUE)
  1144.             normal_video()
  1145.             searching = TRUE -- avoids accidental <CR> insertion
  1146.             else
  1147.             insert(key)
  1148.             end if
  1149.  
  1150.         else
  1151.             insert(key)
  1152.  
  1153.         end if
  1154.  
  1155.         adding_to_kill = FALSE
  1156.  
  1157.         end if
  1158.  
  1159.         if key != CR and key != ESCAPE then
  1160.         searching = FALSE
  1161.         end if
  1162.         position(s_line, s_col)
  1163.         cursor(ED_CURSOR)
  1164.     elsif key != -1 then
  1165.         -- illegal key pressed
  1166.         get_escape(TRUE)  -- give him some help
  1167.     end if
  1168.     end while
  1169. end procedure
  1170.  
  1171. function delete_trailing_white(sequence name)
  1172. -- get rid of blanks, tabs, newlines at end of string
  1173.     while find(name[length(name)], "\n\t ") do
  1174.     name = name[1..length(name)-1]
  1175.     if length(name) = 0 then
  1176.         exit
  1177.     end if
  1178.     end while
  1179.     return name
  1180. end function
  1181.  
  1182. procedure ed(sequence command)
  1183. -- editor main procedure
  1184. -- ed.e is executed by ed.bat
  1185. -- command line will be:
  1186. --    ex ed.e              - get filename etc. from ex.err
  1187. --    ex ed.e filename     - filename specified
  1188.  
  1189.     file_number file_no
  1190.  
  1191.     start_line = 0
  1192.     start_col = 0
  1193.     if length(command) >= 3 then
  1194.     file_name = command[3]
  1195.     else
  1196.     file_name = get_err_line()
  1197.     end if
  1198.     if length(file_name) = 0 then
  1199.     -- we still don't know the file name - so ask user
  1200.     puts(SCREEN, "file name? ")
  1201.     cursor(ED_CURSOR)
  1202.     file_name = gets(KEYB)
  1203.     end if
  1204.     file_name = delete_trailing_white(file_name)
  1205.     if length(file_name) = 0 then
  1206.     stop = TRUE
  1207.     return -- file_name was just whitespace - quit
  1208.     end if
  1209.     file_no = open(file_name, "r")
  1210.  
  1211.     -- turn off multi_color & auto_complete for non .e files
  1212.     dot_e = FALSE
  1213.     if not config[VC_COLOR] then
  1214.     multi_color = FALSE -- mono monitor
  1215.     end if
  1216.     file_name = file_name & ' '
  1217.     dot_e = match(".ex ", file_name) or match(".e ", file_name) or
  1218.         match(".pro ", file_name)
  1219.     file_name = file_name[1..length(file_name)-1]
  1220.     if not dot_e then
  1221.     multi_color = FALSE
  1222.     auto_complete = FALSE
  1223.     end if
  1224.     if multi_color then
  1225.     init_class()
  1226.     end if
  1227.  
  1228.     top_line_set = FALSE
  1229.     adding_to_kill = FALSE
  1230.     modified = FALSE
  1231.     normal_video()
  1232.     wrap(0)
  1233.     if file_no = -1 then
  1234.     buffer = {}
  1235.     clear_screen()
  1236.     puts(SCREEN, "new file - ")
  1237.     puts(SCREEN, file_name)
  1238.     delay(1.5)
  1239.     position(1, 1)
  1240.     puts(SCREEN, BLANK_LINE)
  1241.     else
  1242.     position(1, 1)
  1243.     cursor(NO_CURSOR)
  1244.     read_file(file_no)
  1245.     close(file_no)
  1246.     end if
  1247.     edit_file()
  1248. end procedure
  1249.  
  1250. config = video_config()
  1251.  
  1252. if config[VC_XPIXELS] > 0 then
  1253.     graphics_mode(3)
  1254.     config = video_config()
  1255. end if
  1256.  
  1257. screen_length = config[VC_LINES]
  1258.  
  1259. ed(command_line())
  1260. while length(file_name) > 0 do
  1261.     ed({"ex", "ed.e" , file_name})
  1262. end while
  1263.  
  1264. -- exit editor
  1265. if screen_length != 25 then
  1266.     screen_length = text_rows(25)
  1267. end if
  1268. bk_color(0)
  1269. text_color(0)
  1270. position(screen_length, 1)
  1271. puts(SCREEN, BLANK_LINE)
  1272. position(screen_length, 1)
  1273. text_color(7)
  1274. puts(SCREEN, " \n")
  1275.  
  1276.