예제 #1
0
파일: editor.c 프로젝트: icewwn/fbbs-1
static void real_pos(const editor_t *editor, vector_size_t *x,
		text_line_size_t *y)
{
	*x = 1;
	for (vector_size_t i = editor->allow_edit_begin;
			i < editor->current_line; ++i) {
		if (contains_newline(editor_line(editor, i)))
			++*x;
	}

	*y = editor->screen_pos + 1;
	if (editor->current_line) {
		for (vector_size_t i = editor->current_line - 1;
				i >= editor->allow_edit_begin;) {
			const text_line_t *tl = editor_line(editor, i);
			if (contains_newline(tl))
				break;
			else
				*y += display_width(tl->buf, tl->size);
			if (i)
				--i;
			else
				break;
		}
	}
}
예제 #2
0
/*
** The pTkt object is a ticket change artifact.  Output a detailed
** description of this object.
*/
void ticket_output_change_artifact(Manifest *pTkt, const char *zListType){
  int i;
  int wikiFlags = WIKI_NOBADLINKS;
  const char *zBlock = "<blockquote>";
  const char *zEnd = "</blockquote>";
  if( P("plaintext")!=0 ){
    wikiFlags |= WIKI_LINKSONLY;
    zBlock = "<blockquote><pre class='verbatim'>";
    zEnd = "</pre></blockquote>";
  }
  if( zListType==0 ) zListType = "1";
  cgi_printf("<ol type=\"%s\">\n",(zListType));
  for(i=0; i<pTkt->nField; i++){
    Blob val;
    const char *z;
    z = pTkt->aField[i].zName;
    blob_set(&val, pTkt->aField[i].zValue);
    if( z[0]=='+' ){
      cgi_printf("<li>Appended to %h:%s\n",(&z[1]),(zBlock));
      wiki_convert(&val, 0, wikiFlags);
      cgi_printf("%s</li>\n",(zEnd));
    }else if( blob_size(&val)>50 || contains_newline(&val) ){
      cgi_printf("<li>Change %h to:%s\n",(z),(zBlock));
      wiki_convert(&val, 0, wikiFlags);
      cgi_printf("%s</li>\n",(zEnd));
    }else{
      cgi_printf("<li>Change %h to \"%h\"</li>\n",(z),(blob_str(&val)));
    }
    blob_reset(&val);
  }
  cgi_printf("</ol>\n");
}
예제 #3
0
파일: editor.c 프로젝트: icewwn/fbbs-1
static void display(editor_t *editor, bool ansi)
{
	int line = 0, lines = screen_lines() - 1;
	for (vector_size_t i = editor->window_top;
			i < editor->allow_edit_end && line < lines;
			++i, ++line) {
		text_line_t *tl = editor_line(editor, i);
		if (editor->redraw || tl->redraw) {
			screen_move_clear(line);
			if (ansi) {
				screen_puts(tl->buf, tl->size);
			} else {
				bool marked = i >= editor->mark_begin && i < editor->mark_end;
				if (marked)
					screen_puts("\033[7m", 4);
				const char *last = tl->buf, *end = tl->buf + tl->size;
				for (const char *ptr = tl->buf; ptr < end; ++ptr) {
					if (*ptr == '\033') {
						if (ptr > last)
							screen_puts(last, ptr - last);
						screen_puts("\033[33m*", 0);
						if (marked)
							screen_puts("\033[37m", 0);
						else
							screen_puts("\033[m", 0);
						last = ptr + 1;
					}
				}
				if (end > last) {
					size_t size = end - last - contains_newline(tl);
					if (size)
						screen_puts(last, size);
				}
				if (marked)
					screen_puts("\033[m", 3);
			}
			tl->redraw = false;
		}
	}

	if (editor->redraw) {
		for (; line < lines; ++line) {
			screen_move_clear(line);
			screen_puts("\033[33m~\033[m", 0);
		}
	}

	show_status_line(editor);

	screen_move(editor->current_line - editor->window_top, editor->screen_pos);
	editor->redraw = false;
	return;
}
예제 #4
0
파일: editor.c 프로젝트: icewwn/fbbs-1
/**
 * 从编辑器当前光标所在行开始自动折行
 * @param editor 编辑器
 * @return 折行次数
 */
static int wrap_long_lines(editor_t *editor)
{
	vector_size_t saved_line, line;
	saved_line = line = editor->current_line;
	text_line_size_t saved_pos = editor->buffer_pos;

	while (1) {
		text_line_t *tl = editor_line(editor, line);
		const char *p = seek_to_display_width(tl->buf, tl->size, WRAP_MARGIN);
		if (p >= tl->buf + tl->size)
			break;

		editor->redraw = true;

		// 如果当前光标被折行,记录下新位置
		if (saved_line == line && p <= tl->buf + saved_pos) {
			saved_pos -= p - tl->buf;
			saved_line = line + 1;
		}

		++line;
		text_line_t *next_tl = editor_line(editor, line);
		if (contains_newline(tl) || !next_tl
				|| line >= editor->allow_edit_end) {
			text_line_t new_tl = { .buf = NULL };
			vector_insert(&editor->lines, line, &new_tl);
			tl = editor_line(editor, line - 1);
			++editor->allow_edit_end;
		}

		++editor->current_line;
		editor->buffer_pos = 0;
		if (raw_insert(editor, p, tl->size - (p - tl->buf)))
			tl->size = p - tl->buf;
		else
			break;
	}
예제 #5
0
/*
** COMMAND: ticket*
** Usage: %fossil ticket SUBCOMMAND ...
**
** Run various subcommands to control tickets
**
**   %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options?
**
**     options can be:
**       ?-l|--limit LIMITCHAR?
**       ?-q|--quote?
**       ?-R|--repository FILE?
**
**     Run the ticket report, identified by the report format title
**     used in the gui. The data is written as flat file on stdout,
**     using TAB as separator. The separator can be changed using
**     the -l or --limit option.
**
**     If TICKETFILTER is given on the commandline, the query is
**     limited with a new WHERE-condition.
**       example:  Report lists a column # with the uuid
**                 TICKETFILTER may be [#]='uuuuuuuuu'
**       example:  Report only lists rows with status not open
**                 TICKETFILTER: status != 'open'
**     If the option -q|--quote is used, the tickets are encoded by
**     quoting special chars(space -> \\s, tab -> \\t, newline -> \\n,
**     cr -> \\r, formfeed -> \\f, vtab -> \\v, nul -> \\0, \\ -> \\\\).
**     Otherwise, the simplified encoding as on the show report raw
**     page in the gui is used. This has no effect in JSON mode.
**
**     Instead of the report title its possible to use the report
**     number. Using the special report number 0 list all columns,
**     defined in the ticket table.
**
**   %fossil ticket list fields
**
**     list all fields, defined for ticket in the fossil repository
**
**   %fossil ticket list reports
**
**     list all ticket reports, defined in the fossil repository
**
**   %fossil ticket set TICKETUUID (FIELD VALUE)+ ?-q|--quote?
**   %fossil ticket change TICKETUUID (FIELD VALUE)+ ?-q|--quote?
**
**     change ticket identified by TICKETUUID and set the value of
**     field FIELD to VALUE.
**
**     Field names as defined in the TICKET table.  By default, these
**     names include: type, status, subsystem, priority, severity, foundin,
**     resolution, title, and comment, but other field names can be added
**     or substituted in customized installations.
**
**     If you use +FIELD, the VALUE Is appended to the field FIELD.
**     You can use more than one field/value pair on the commandline.
**     Using -q|--quote  enables the special character decoding as
**     in "ticket show". So it's possible, to set multiline text or
**     text with special characters.
**
**   %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote?
**
**     like set, but create a new ticket with the given values.
**
**   %fossil ticket history TICKETUUID
**
**     Show the complete change history for the ticket
**
** The values in set|add are not validated against the definitions
** given in "Ticket Common Script".
*/
void ticket_cmd(void){
  int n;
  const char *zUser;
  const char *zDate;
  const char *zTktUuid;

  /* do some ints, we want to be inside a checkout */
  db_find_and_open_repository(0, 0);
  user_select();

  zUser = find_option("user-override",0,1);
  if( zUser==0 ) zUser = g.zLogin;
  zDate = find_option("date-override",0,1);
  if( zDate==0 ) zDate = "now";
  zDate = date_in_standard_format(zDate);
  zTktUuid = find_option("uuid-override",0,1);
  if( zTktUuid && (strlen(zTktUuid)!=40 || !validate16(zTktUuid,40)) ){
    fossil_fatal("invalid --uuid-override: must be 40 characters of hex");
  }

  /*
  ** Check that the user exists.
  */
  if( !db_exists("SELECT 1 FROM user WHERE login=%Q", zUser) ){
    fossil_fatal("no such user: %s", zUser);
  }

  if( g.argc<3 ){
    usage("add|change|list|set|show|history");
  }
  n = strlen(g.argv[2]);
  if( n==1 && g.argv[2][0]=='s' ){
    /* set/show cannot be distinguished, so show the usage */
    usage("add|change|list|set|show|history");
  }
  if( strncmp(g.argv[2],"list",n)==0 ){
    if( g.argc==3 ){
      usage("list fields|reports");
    }else{
      n = strlen(g.argv[3]);
      if( !strncmp(g.argv[3],"fields",n) ){
        /* simply show all field names */
        int i;

        /* read all available ticket fields */
        getAllTicketFields();
        for(i=0; i<nField; i++){
          printf("%s\n",aField[i].zName);
        }
      }else if( !strncmp(g.argv[3],"reports",n) ){
        rpt_list_reports();
      }else{
        fossil_fatal("unknown ticket list option '%s'!",g.argv[3]);
      }
    }
  }else{
    /* add a new ticket or set fields on existing tickets */
    tTktShowEncoding tktEncoding;

    tktEncoding = find_option("quote","q",0) ? tktFossilize : tktNoTab;
    
    if( strncmp(g.argv[2],"show",n)==0 ){
      if( g.argc==3 ){
        usage("show REPORTNR");
      }else{
        const char *zRep = 0;
        const char *zSep = 0;
        const char *zFilterUuid = 0;
        zSep = find_option("limit","l",1);
        zRep = g.argv[3];
        if( !strcmp(zRep,"0") ){
          zRep = 0;
        }
        if( g.argc>4 ){
          zFilterUuid = g.argv[4];
        }
        rptshow( zRep, zSep, zFilterUuid, tktEncoding );
      }
    }else{
      /* add a new ticket or update an existing ticket */
      enum { set,add,history,err } eCmd = err;
      int i = 0;
      Blob tktchng, cksum;

      /* get command type (set/add) and get uuid, if needed for set */
      if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 ||
         strncmp(g.argv[2],"history",n)==0 ){
        if( strncmp(g.argv[2],"history",n)==0 ){
          eCmd = history;
        }else{
          eCmd = set;
        }
        if( g.argc==3 ){
          usage("set|change|history TICKETUUID");
        }
        zTktUuid = db_text(0, 
          "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3]
        );
        if( !zTktUuid ){
          fossil_fatal("unknown ticket: '%s'!",g.argv[3]);
        }
        i=4;
      }else if( strncmp(g.argv[2],"add",n)==0 ){
        eCmd = add;
        i = 3;
        if( zTktUuid==0 ){
          zTktUuid = db_text(0, "SELECT lower(hex(randomblob(20)))");
        }
      }
      /* none of set/add, so show the usage! */
      if( eCmd==err ){
        usage("add|fieldlist|set|show|history");
      }

      /* we just handle history separately here, does not get out */
      if( eCmd==history ){
        Stmt q;
        int tagid;

        if ( i != g.argc ){
          fossil_fatal("no other parameters expected to %s!",g.argv[2]);
        }
        tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
                       zTktUuid);
        if( tagid==0 ){
          fossil_fatal("no such ticket %h", zTktUuid);
        }  
        db_prepare(&q,
          "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL"
          "  FROM event, blob"
          " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
          "   AND blob.rid=event.objid"
          " UNION "
          "SELECT datetime(mtime%s), attachid, uuid, src, "
          "       filename, user"
          "  FROM attachment, blob"
          " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
          "   AND blob.rid=attachid"
          " ORDER BY 1 DESC",
          timeline_utc(), tagid, timeline_utc(), tagid
        );
        while( db_step(&q)==SQLITE_ROW ){
          Manifest *pTicket;
          char zShort[12];
          const char *zDate = db_column_text(&q, 0);
          int rid = db_column_int(&q, 1);
          const char *zChngUuid = db_column_text(&q, 2);
          const char *zFile = db_column_text(&q, 4);
          memcpy(zShort, zChngUuid, 10);
          zShort[10] = 0;
          if( zFile!=0 ){
            const char *zSrc = db_column_text(&q, 3);
            const char *zUser = db_column_text(&q, 5);
            if( zSrc==0 || zSrc[0]==0 ){
              fossil_print("Delete attachment %s\n", zFile);
            }else{
              fossil_print("Add attachment %s\n", zFile);
            }
            fossil_print(" by %s on %s\n", zUser, zDate);
          }else{
            pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
            if( pTicket ){
              int i;

              fossil_print("Ticket Change by %s on %s:\n",
                           pTicket->zUser, zDate);
              for(i=0; i<pTicket->nField; i++){
                Blob val;
                const char *z;
                z = pTicket->aField[i].zName;
                blob_set(&val, pTicket->aField[i].zValue);
                if( z[0]=='+' ){
                  fossil_print("  Append to ");
            z++;
          }else{
            fossil_print("  Change ");
          }
          fossil_print("%h: ",z);
          if( blob_size(&val)>50 || contains_newline(&val)) {
                  fossil_print("\n    ",blob_str(&val));
                  comment_print(blob_str(&val),4,79);
                }else{
                  fossil_print("%s\n",blob_str(&val));
                }
                blob_reset(&val);
              }
            }
            manifest_destroy(pTicket);
          }
        }
        db_finalize(&q);
        return;
      }
      /* read all given ticket field/value pairs from command line */
      if( i==g.argc ){
        fossil_fatal("empty %s command aborted!",g.argv[2]);
      }
      getAllTicketFields();
      /* read commandline and assign fields in the aField[].zValue array */
      while( i<g.argc ){
        char *zFName;
        char *zFValue;
        int j;
        int append = 0;

        zFName = g.argv[i++];
        if( i==g.argc ){
          fossil_fatal("missing value for '%s'!",zFName);
        }
        zFValue = g.argv[i++];
        if( tktEncoding == tktFossilize ){
          zFValue=mprintf("%s",zFValue);
          defossilize(zFValue);
        }
        append = (zFName[0] == '+');
        if (append){
          zFName++;
        }
        j = fieldId(zFName);
        if( j == -1 ){
          fossil_fatal("unknown field name '%s'!",zFName);
        }else{
          if (append) {
            aField[j].zAppend = zFValue;
          } else {
            aField[j].zValue = zFValue;
          }
        }
      }

      /* now add the needed artifacts to the repository */
      blob_zero(&tktchng);
      /* add the time to the ticket manifest */
      blob_appendf(&tktchng, "D %s\n", zDate);
      /* append defined elements */
      for(i=0; i<nField; i++){
        char *zValue = 0;
        char *zPfx;

        if (aField[i].zAppend && aField[i].zAppend[0] ){
          zPfx = " +";
          zValue = aField[i].zAppend;
        } else if( aField[i].zValue && aField[i].zValue[0] ){
          zPfx = " ";
          zValue = aField[i].zValue;
        } else {
          continue;
        }
        if( memcmp(aField[i].zName, "private_", 8)==0 ){
          zValue = db_conceal(zValue, strlen(zValue));
          blob_appendf(&tktchng, "J%s%s %s\n", zPfx, aField[i].zName, zValue);
        }else{
          blob_appendf(&tktchng, "J%s%s %#F\n", zPfx,
                       aField[i].zName, strlen(zValue), zValue);
        }
      }
      blob_appendf(&tktchng, "K %s\n", zTktUuid);
      blob_appendf(&tktchng, "U %F\n", zUser);
      md5sum_blob(&tktchng, &cksum);
      blob_appendf(&tktchng, "Z %b\n", &cksum);
      if( ticket_put(&tktchng, zTktUuid, 0) ){
        fossil_fatal("%s\n", g.zErrMsg);
      }else{
        fossil_print("ticket %s succeeded for %s\n",
             (eCmd==set?"set":"add"),zTktUuid);
      }
    }
  }
}