You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下如何用纯Pascal开发支持方向键交互的简易文本编辑器

Linux平台纯Pascal简易文本编辑器实现方案

现有基础与问题

当前已实现的代码支持新建文件、逐字符写入、按CTRL-Z退出写入流程,但存在两个核心缺陷:

  • 仅支持新建覆盖写入,无法打开已有文件编辑
  • 按键读取依赖行缓冲,没有处理扩展按键,无法通过方向键移动光标,不能在任意位置编辑
    现有代码如下:
program textos;
uses crt;

var
  file_name: string;
  f: text;
  c: char;
  s: string;
begin
  writeln('Enter the name of the file to create');
  readln(file_name);
  writeln('Enter your text to be recorded in the file ', file_name);
  writeln('End with CTRL-Z followed by ENTER');writeln;
  assign(f, file_name);
  rewrite(f);
  repeat;
    read(c);
    write(f,c);
  until c=#26; {is equivalent to chr(26), which is CTRL-Z}
  close(f);
  writeln('Now look at the file ', file_name, ' in your directory');
  writeln;
  writeln('Reading now from disk line by line and putting on screen:');
  reset(f); {opening for reading}
  while (not eof(f)) do
    begin
      readln(f,s);
      writeln(s);
    end;
end.

核心实现思路

1. 整体架构调整

放弃边输入边写磁盘的逻辑,所有编辑操作在内存缓冲区完成:

  • 用动态字符串数组作为文本缓冲区,数组每个元素对应文本的一行
  • 维护两个全局变量存储当前光标坐标:cur_x记录列位置,cur_y记录行位置
  • 程序启动时先让用户选择新建/打开文件:新建则初始化空缓冲区,打开则逐行读取文件内容存入缓冲区,之后把缓冲区内容全量绘制到屏幕,光标定位到(1,1)位置进入编辑循环
  • 触发保存操作时,再把缓冲区全量写入磁盘文件

2. 方向键与扩展按键处理

已引入的crt单元已经提供了无回显、不需要回车确认的读键函数ReadKey,以及直接移动终端光标的函数GotoXY,不需要额外调用系统API或者第三方库。
方向键、功能键这类扩展按键的读取规则是:ReadKey第一次读到的字符是#0(空字符),此时需要再读一次字符,第二个字符的数值对应具体按键:

  • 上方向键:#72
  • 下方向键:#80
  • 左方向键:#75
  • 右方向键:#77
    读到对应方向键时,修改cur_x/cur_y坐标即可,注意做边界校验:
  • 行坐标不能小于1,不能大于缓冲区总行数
  • 列坐标不能小于1,不能大于当前行长度+1(行尾位置)
  • 上下移动时如果当前列位置超过目标行的总长度,自动把光标对齐到目标行行尾
    坐标修改完成后调用GotoXY(cur_x, cur_y)就能把终端光标移动到对应位置。

3. 编辑逻辑处理

  • 普通可打印字符:读到后插入到当前光标所在的缓冲区位置,光标右移一位,同步在屏幕输出字符,重绘当前行光标后的内容避免显示错位
  • 退格键(#8):删除光标前一个字符,后续内容前移,同步更新屏幕
  • 回车键(#13):拆分当前行,把光标后的内容作为新行插入到缓冲区当前行的下位置,光标移动到新行行首
  • 快捷键保留:可以继续用CTRL-Z(#26)作为退出触发键,新增CTRL-S(#19)作为手动保存快捷键

核心编辑循环参考代码

var
  ch: char;
  cur_x, cur_y: integer;
  buffer: array of string;
  f: text;
  file_name: string;
  s: string;
begin
  { 此处省略:新建/打开文件选择、文件内容读入buffer、屏幕初始绘制逻辑 }
  cur_x := 1;
  cur_y := 1;
  GotoXY(cur_x, cur_y);
  repeat
    ch := ReadKey;
    if ch = #0 then
    begin
      ch := ReadKey;
      case ch of
        #72: { 上方向键 }
          if cur_y > 1 then
          begin
            Dec(cur_y);
            if cur_x > Length(buffer[cur_y-1]) + 1 then
              cur_x := Length(buffer[cur_y-1]) + 1;
            GotoXY(cur_x, cur_y);
          end;
        #80: { 下方向键 }
          if cur_y < Length(buffer) then
          begin
            Inc(cur_y);
            if cur_x > Length(buffer[cur_y-1]) + 1 then
              cur_x := Length(buffer[cur_y-1]) + 1;
            GotoXY(cur_x, cur_y);
          end;
        #75: { 左方向键 }
          if cur_x > 1 then
          begin
            Dec(cur_x);
            GotoXY(cur_x, cur_y);
          end;
        #77: { 右方向键 }
          if cur_x <= Length(buffer[cur_y-1]) then
          begin
            Inc(cur_x);
            GotoXY(cur_x, cur_y);
          end;
      end;
    end
    else
      case ch of
        #26: Break; { CTRL-Z 退出编辑 }
        #19: { CTRL-S 手动保存 }
          begin
            Assign(f, file_name);
            Rewrite(f);
            for s in buffer do Writeln(f, s);
            Close(f);
          end;
        #8:  { 退格键删除逻辑,补全边界处理即可 }
          begin
            if cur_x > 1 then
            begin
              Delete(buffer[cur_y-1], cur_x-1, 1);
              Dec(cur_x);
              { 此处补全屏幕重绘逻辑 }
              GotoXY(cur_x, cur_y);
            end;
          end;
        #13: { 回车键换行逻辑 }
          begin
            Insert('', buffer, cur_y);
            buffer[cur_y] := Copy(buffer[cur_y-1], cur_x, Length(buffer[cur_y-1]) - cur_x + 1);
            Delete(buffer[cur_y-1], cur_x, Length(buffer[cur_y-1]) - cur_x + 1);
            Inc(cur_y);
            cur_x := 1;
            ClrEol;
            Writeln;
            { 此处补全新行后续内容的屏幕重绘逻辑 }
            GotoXY(cur_x, cur_y);
          end;
        else { 普通可打印字符输入 }
          begin
            Insert(ch, buffer[cur_y-1], cur_x);
            Write(ch);
            Inc(cur_x);
            { 此处补全光标后内容的重绘逻辑 }
            GotoXY(cur_x, cur_y);
          end;
      end;
  until False;
end.

注意事项

  • Pascal中动态字符串数组下标默认从0开始,字符串下标从1开始,处理坐标和缓冲区对应关系时不要错位
  • 所有修改缓冲区的操作都要同步更新屏幕显示,否则会出现内容和光标位置错位的问题
  • 不需要额外依赖ncurses之类的第三方库,crt单元提供的功能足够完成基础编辑器的所有交互需求

内容的提问来源于stack exchange,提问作者Puser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:27:26