class CLine
{
  CLine *next,*last;
  U8 *line;
};

U0 EdLiteUpdate(CLine *head,CLine *cur_line,I64 cur_col,I64 line_start_col)
{
  I64 ch,i,j,k,k2,cursor_col,cursor_row=-1;
  U8 *st;
  CLine *tmpl=cur_line;
  Bool done_eof=FALSE;
  text.raw_col=0;
  for (i=0;i<text.rows/2;i++)
    if (tmpl->last!=head)
      tmpl=tmpl->last;
  for (i=0;i<text.rows;i++) {
    if (cursor_row<0 && tmpl==cur_line) {
      k=0;
      for (j=0;j<cur_col;j++)
        if (tmpl->line[j]=='\t')
          k=(k+8)&~7;
        else
          k++;
      cursor_col=k;
      cursor_row=i;
    }
    if (tmpl!=head) {
      st=tmpl->line;
      k=0;
      j=0;
      while (ch=*st++) {
        if (ch=='\t')
          k2=(k+8)&~7;
        else
          k2=k+1;
        if (line_start_col<=k<line_start_col+text.cols) {
          '' ch;
          j=k2-line_start_col;
        }
        k=k2;
      }
      if (j<text.cols)
        '\n';
      tmpl=tmpl->next;
    } else {
      if (!done_eof) {
        '<EOF>';
        done_eof=TRUE;
      }
      '\n';
    }
  }
  text.raw_col=text.cols*cursor_row+cursor_col-line_start_col;
  RawPutChar(0x7F);
}

Bool EdLite(U8 *filename,I64 num=1,I64 edf_dof_flags=0)
{//Light weight text editor for debugging.
  U8 *src,*src2,*src3,*dst,*buf,*bin_data=NULL;
  I64 i,cnt=0,ch,sc,size,bin_size=0,line_start_col=0,cur_col=0,
        old_raw_flags=text.raw_flags;
  CLine head,*tmpl,*tmpl1,*cur_line;
  Bool  res=FALSE,
        old_raw=Raw(ON),
        old_debug=DbgMode(ON),
        old_single=SingleUser(ON);

  if (!filename) filename=blkdev.tmp_filename;
  buf=FileRead(filename,&size);

  PUSHFD
  CLI
  text.raw_flags=text.raw_flags&~RWF_SCROLL|RWF_SHOW_DOLLAR;
  kbd.scan_code=0;
  QueInit(&head);
  head.line=StrNew("");

  if (buf) {
    src=buf;
    while (*src) {
      src2=src;
      while ((ch=*src++) && ch!='\r' && ch!='\n');
      src--;
      *src++=0;
      if (!ch)
        src--;
      while (ch=='\r' && *src=='\n' || *src==CH_CURSOR)
        src++;
      dst=src3=src2;
      while (ch=*src3++)
        if (ch!='\n' && ch!=CH_CURSOR)
          *dst++=ch;
      *dst=0;

      tmpl=MAlloc(sizeof(CLine));
      tmpl->line=StrNew(src2);
      QueIns(tmpl,head.last);
      cnt++;
    }

    if (src+1-buf<size) {
      bin_data=MAlloc(bin_size=size-(src-buf));
      MemCpy(bin_data,src,bin_size);
    }
    Free(buf);
    res=TRUE;
  }

  cur_line=head.next;
  if (--num<0)
    res=FALSE;
  else {
    if (num<=cnt)
      while (num--)
        cur_line=cur_line->next;
    else {
      cur_line=&head;
      res=FALSE;
    }
  }
  do {
    if (cur_line==&head)
      cur_col=0;
    while (cur_col-line_start_col<0)
      line_start_col-=8;
    while (cur_col-line_start_col>=text.cols)
      line_start_col+=8;
    EdLiteUpdate(&head,cur_line,cur_col,line_start_col);
    switch (ch=GetKey(&sc,FALSE,TRUE)) {
      case 0:
        switch (sc.u8[0]) {
          case SC_CURSOR_UP:
            if (cur_line->last!=&head)
              cur_line=cur_line->last;
            if (cur_col>StrLen(cur_line->line))
              cur_col=StrLen(cur_line->line);
            break;
          case SC_CURSOR_DOWN:
            if (cur_line!=&head)
              cur_line=cur_line->next;
            if (cur_col>StrLen(cur_line->line))
              cur_col=StrLen(cur_line->line);
            break;
          case SC_CURSOR_RIGHT:
            cur_col++;
            if (cur_col>StrLen(cur_line->line)) {
              tmpl=cur_line->next;
              if (tmpl!=&head) {
                cur_col=0;
                cur_line=tmpl;
              } else
                cur_col=StrLen(cur_line->line);
            }
            break;
          case SC_CURSOR_LEFT:
            if (cur_col)
              cur_col--;
            else {
              tmpl=cur_line->last;
              if (tmpl!=&head) {
                cur_line=tmpl;
                cur_col=StrLen(tmpl->line);
              }
            }
            break;
          case SC_PAGE_UP:
            for (i=1;i<text.rows;i++) {
              if (cur_line->last!=&head)
                cur_line=cur_line->last;
              if (cur_col>StrLen(cur_line->line))
                cur_col=StrLen(cur_line->line);
            }
            break;
          case SC_PAGE_DOWN:
            for (i=1;i<text.rows;i++) {
              if (cur_line!=&head)
                cur_line=cur_line->next;
              if (cur_col>StrLen(cur_line->line))
                cur_col=StrLen(cur_line->line);
            }
            break;
          case SC_DELETE:
            if (cur_col==StrLen(cur_line->line)) {
              tmpl=cur_line->next;
              if (cur_line!=&head && tmpl!=&head) {
                src=MStrPrint("%s%s",cur_line->line,tmpl->line);
                Free(cur_line->line);
                Free(tmpl->line);
                cur_line->line=src;
                QueRem(tmpl);
                Free(tmpl);
              }
            } else
              StrCpy(cur_line->line+cur_col,cur_line->line+cur_col+1);
            break;
        }
        break;
      case '\n':
      case '\r':
        tmpl=MAlloc(sizeof(CLine));
        tmpl->line=StrNew(cur_line->line+cur_col);
        cur_line->line[cur_col]=0;
        QueIns(tmpl,cur_line);
        cur_line=tmpl;
        cur_col=0;
        break;
      case CH_BACKSPACE:
        if (cur_col) {
          StrCpy(cur_line->line+cur_col-1,cur_line->line+cur_col);
          cur_col--;
        } else if (cur_line!=&head && cur_line->last!=&head) {
          tmpl=cur_line->last;
          src=MStrPrint("%s%s",tmpl->line,cur_line->line);
          cur_col=StrLen(tmpl->line);
          Free(cur_line->line);
          Free(tmpl->line);
          tmpl->line=src;
          QueRem(cur_line);
          Free(cur_line);
          cur_line=tmpl;
        }
        break;
      case CH_CTRLY:
        if (cur_line!=&head) {
          tmpl=cur_line;
          cur_line=cur_line->next;
          QueRem(tmpl);
          Free(tmpl->line);
          Free(tmpl);
          cur_col=0;
        }
        break;
      default:
        if (Bt(char_bmp_printable,ch)) {
          if (cur_line==&head) {
            cur_line=MAlloc(sizeof(CLine));
            cur_line->line=StrNew("");
            QueIns(cur_line,head.last);
          }
          src=MAlloc(StrLen(cur_line->line)+2);
          MemCpy(src,cur_line->line,cur_col);
          src[cur_col]=ch;
          if (cur_col<StrLen(cur_line->line))
            StrCpy(src+cur_col+1,cur_line->line+cur_col);
          else
            src[cur_col+1]=0;
          Free(cur_line->line);
          cur_line->line=src;
          cur_col++;
        }
    }
  } while (ch!=CH_SHIFT_ESC && ch!=CH_ESC);

  if (ch!=CH_ESC) {
    if (edf_dof_flags&EDF_WAS_WRITE)
      res=FALSE;
  } else {
    size=bin_size;

    tmpl=head.next;
    while (tmpl!=&head) {
      size+=StrLen(tmpl->line)+1;
      tmpl=tmpl->next;
    }

    buf=dst=MAlloc(size);
    tmpl=head.next;
    while (tmpl!=&head) {
      i=StrLen(tmpl->line);
      MemCpy(dst,tmpl->line,i);
      dst+=i;
      *dst++='\n';
      tmpl=tmpl->next;
    }
    if (bin_data)
      MemCpy(dst,bin_data,bin_size);
    FileWrite(filename,buf,size);
    Free(buf);

    if (edf_dof_flags&EDF_WAS_WRITE)
      res=TRUE;
  }

  tmpl=head.next;
  while (tmpl!=&head) {
    tmpl1=tmpl->next;
    QueRem(tmpl);
    Free(tmpl->line);
    Free(tmpl);
    tmpl=tmpl1;
  }
  Free(head.line);
  Free(bin_data);
  Raw(old_raw);
  DbgMode(old_debug);
  SingleUser(old_single);
  text.raw_flags=text.raw_flags&~RWF_SHOW_DOLLAR|old_raw_flags&RWF_SHOW_DOLLAR;
  POPFD
  return res;
}

U0 ToFileLine(U8 *_fl_file_line,U8 **_filename,I64 *_linenum)
{//"FI:D:/Dir/File.HC,123" to "D:/Dir/File.HC" and 123.
  U8 *st,*fl_file_line=StrNew(_fl_file_line);
  I64 linenum;
  StrFirstRem(fl_file_line,":");
  st=StrNew(fl_file_line);
  StrLastRem(fl_file_line,",",st);
  linenum=Str2I64(st);
  Free(st);
  *_filename=fl_file_line;
  *_linenum=linenum;
}

Bool EdLiteFileLine(U8 *fl_file_line,I64 edf_dof_flags=0)
{
  Bool res;
  U8 *filename;
  I64 linenum;
  ToFileLine(fl_file_line,&filename,&linenum);
  res=EdLite(filename,linenum,edf_dof_flags);
  Free(filename);
  return res;
}

U0 FixSet(U8 *filename,I64 line)
{//Compiler calls this to set file line for Fix
  U8 *st=MStrPrint("FL:%s,%d",filename,line);
  while (LBts(&sys_semas[SEMA_FIX],0))
    Yield;
  Free(dbg.fix_file_line);
  dbg.fix_file_line=AStrNew(st);
  LBtr(&sys_semas[SEMA_FIX],0);
}

Bool Fix(I64 edf_dof_flags=0)
{//Jump to last err src code to fix it.
  U8 *st;
  Bool res=FALSE;

  while (LBts(&sys_semas[SEMA_FIX],0))
    Yield;
  st=StrNew(dbg.fix_file_line);
  LBtr(&sys_semas[SEMA_FIX],0);

  if (st) {
    if (IsRaw)
      res=EdLiteFileLine(st,edf_dof_flags);
    else
      res=Ed(st,edf_dof_flags);
  }
  Free(st);
  return res;
}