SQLite

Check-in [2d0a8a6c38]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Teach the CLI that VT100-escape codes that do things like change font colors have zero-width for the purpose of laying out the columns of a table.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 2d0a8a6c38981552748ff5fc2eeba86590e0f116abac260a7fc9318de0a0dbda
User & Date: drh 2025-03-21 18:15:13.290
Context
2025-03-21
21:13
Fix a multi-arg expr call in proj-current-proc-name (must be single-arg for portability). (check-in: 914768f3f5 user: stephan tags: trunk)
18:15
Teach the CLI that VT100-escape codes that do things like change font colors have zero-width for the purpose of laying out the columns of a table. (check-in: 2d0a8a6c38 user: drh tags: trunk)
16:49
Flesh out the new proc-debug and its infrastructure a bit. (check-in: ba7f1ff0d7 user: stephan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/shell.c.in.
779
780
781
782
783
784
785

















786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801

802
803
804
805
806
807
808
809
810
811
812
813


814
815
816
817
818
819
820
    }else{
      i++;
    }
  }
  return n;
}
#endif


















/*
** Output string zUtf to stdout as w characters.  If w is negative,
** then right-justify the text.  W is the width in UTF-8 characters, not
** in bytes.  This is different from the %*.*s specification in printf
** since with %*.*s the width is measured in bytes, not characters.
**
** Take into account zero-width and double-width Unicode characters.
** In other words, a zero-width character does not count toward the
** the w limit.  A double-width character counts as two.
*/
static void utf8_width_print(FILE *out, int w, const char *zUtf){
  const unsigned char *a = (const unsigned char*)zUtf;
  unsigned char c;
  int i = 0;
  int n = 0;

  int aw = w<0 ? -w : w;
  if( zUtf==0 ) zUtf = "";
  while( (c = a[i])!=0 ){
    if( (c&0xc0)==0xc0 ){
      int u;
      int len = decodeUtf8(a+i, &u);
      int x = cli_wcwidth(u);
      if( x+n>aw ){
        break;
      }
      i += len;
      n += x;


    }else if( n>=aw ){
      break;
    }else{
      n++;
      i++;
    }
  }







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
















>












>
>







779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
    }else{
      i++;
    }
  }
  return n;
}
#endif

/*
** Check to see if z[] is a valid VT100 escape.  If it is, then
** return the number of bytes in the escape sequence.  Return 0 if
** z[] is not a VT100 escape.
**
** This routine assumes that z[0] is \033 (ESC).
*/
static int isVt100(const unsigned char *z){
  int i;
  if( z[1]!='[' ) return 0;
  i = 2;
  while( z[i]>=0x30 && z[i]<=0x3f ){ i++; }
  while( z[i]>=0x20 && z[i]<=0x2f ){ i++; }
  if( z[i]<0x40 || z[i]>0x7e ) return 0;
  return i+1;
}

/*
** Output string zUtf to stdout as w characters.  If w is negative,
** then right-justify the text.  W is the width in UTF-8 characters, not
** in bytes.  This is different from the %*.*s specification in printf
** since with %*.*s the width is measured in bytes, not characters.
**
** Take into account zero-width and double-width Unicode characters.
** In other words, a zero-width character does not count toward the
** the w limit.  A double-width character counts as two.
*/
static void utf8_width_print(FILE *out, int w, const char *zUtf){
  const unsigned char *a = (const unsigned char*)zUtf;
  unsigned char c;
  int i = 0;
  int n = 0;
  int k;
  int aw = w<0 ? -w : w;
  if( zUtf==0 ) zUtf = "";
  while( (c = a[i])!=0 ){
    if( (c&0xc0)==0xc0 ){
      int u;
      int len = decodeUtf8(a+i, &u);
      int x = cli_wcwidth(u);
      if( x+n>aw ){
        break;
      }
      i += len;
      n += x;
    }else if( c==0x1b && (k = isVt100(&a[i]))>0 ){
      i += k;       
    }else if( n>=aw ){
      break;
    }else{
      n++;
      i++;
    }
  }
3994
3995
3996
3997
3998
3999
4000




4001
4002
4003

4004
4005
4006
4007
4008
4009
4010
      do{
        n++;
        j++;
      }while( (n&7)!=0 && n<mxWidth );
      i++;
      continue;
    }




    n++;
    j += 3;
    i++;

  }
  if( n>=mxWidth && bWordWrap  ){
    /* Perhaps try to back up to a better place to break the line */
    for(k=i; k>i/2; k--){
      if( IsSpace(z[k-1]) ) break;
    }
    if( k<=i/2 ){







>
>
>
>
|
|
|
>







4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
      do{
        n++;
        j++;
      }while( (n&7)!=0 && n<mxWidth );
      i++;
      continue;
    }
    if( c==0x1b && p->eEscMode==SHELL_ESC_OFF && (k = isVt100(&z[i]))>0 ){
      i += k;
      j += k;
    }else{
      n++;
      j += 3;
      i++;
    }
  }
  if( n>=mxWidth && bWordWrap  ){
    /* Perhaps try to back up to a better place to break the line */
    for(k=i; k>i/2; k--){
      if( IsSpace(z[k-1]) ) break;
    }
    if( k<=i/2 ){
4062
4063
4064
4065
4066
4067
4068
4069






4070

4071

4072
4073
4074
4075
4076
4077
4078
        zOut[j++] = 0x90;
        zOut[j++] = 0x80 + c;
        break;
      case SHELL_ESC_ASCII:
        zOut[j++] = '^';
        zOut[j++] = 0x40 + c;
        break;
      case SHELL_ESC_OFF:






        zOut[j++] = c;

        break;

    }
    i++;
  }
  zOut[j] = 0;
  return (char*)zOut;
}








|
>
>
>
>
>
>
|
>

>







4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
        zOut[j++] = 0x90;
        zOut[j++] = 0x80 + c;
        break;
      case SHELL_ESC_ASCII:
        zOut[j++] = '^';
        zOut[j++] = 0x40 + c;
        break;
      case SHELL_ESC_OFF: {
        int nn;
        if( c==0x1b && (nn = isVt100(&z[i]))>0 ){
          memcpy(&zOut[j], &z[i], nn);
          j += nn;
          i += nn - 1;
        }else{
          zOut[j++] = c;
        }
        break;
      }
    }
    i++;
  }
  zOut[j] = 0;
  return (char*)zOut;
}

Added test/vt100-a.sql.






































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
** Run this script using the "sqlite3" command-line shell
** test test formatting of output text that contains
** vt100 escape sequences.
*/
.mode box -escape off
CREATE TEMP TABLE t1(a,b,c);
INSERT INTO t1 VALUES
  ('one','twotwotwo','thirty-three'),
  (unistr('\u001b[91mRED\u001b[0m'),'fourfour','fifty-five'),
  ('six','seven','eighty-eight');
.print With -escape off
SELECT * FROM t1;
.mode box -escape ascii
.print With -escape ascii
SELECT * FROM t1;
.mode box -escape symbol
.print With -escape symbol
SELECT * FROM t1;