Introduction
Introduction Statistics Contact Development Disclaimer Help
yank buffer and initial copy/cut/paste support - gramscii - A simple editor for…
Log
Files
Refs
Tags
README
LICENSE
---
commit eebc645dee0d15871d6cc46f156d424cd916b191
parent a99759398841d86928c7ad4d8248f907765cbeb2
Author: KatolaZ <[email protected]>
Date: Tue, 30 Jul 2019 12:15:54 +0100
yank buffer and initial copy/cut/paste support
Diffstat:
M Makefile | 2 +-
M TODO | 11 +++++++----
M draw.c | 11 +++++++++++
M files.c | 6 +++---
M gramscii.1 | 20 ++++++++++++++++++--
M gramscii.h | 36 ++++++++++++++++++++++++-----…
A lineset.c | 117 +++++++++++++++++++++++++++++…
M main.c | 11 ++++-------
M screen.c | 117 ++++++++++-------------------…
9 files changed, 227 insertions(+), 104 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -3,7 +3,7 @@
include config.mk
-SRC = main.c draw.c screen.c files.c
+SRC = main.c draw.c screen.c files.c lineset.c
INC = config.h gramscii.h
all: options gramscii
diff --git a/TODO b/TODO
@@ -6,8 +6,8 @@
- use [ENTER] to exit from text insert
- maybe move "text" mode to "t"
- implement ellipse
-- filled box (B)
-- manage fill character (as for other styles)
+- (?) filled box (B)
+- (?) manage filled box character (as for other styles)
- implement comment (#: ignore until the end of the line)
+ parse control characters
+ parse arrows (text-mode will allow movements as well)
@@ -15,15 +15,18 @@
- (?) remove extra blanks until EOL when saving to file
+ visual selection
- crop-to
- - yank/put
+ * yank
* fill
- * delete
+ * cut
- undo (by storing lines changed across insert/remove operations)
- manage special chars (DEL/CANC) during text insert
(also do not print unmanaged chars!)
- allow scrolling (both vertical and horizontal)
- catch SIGWINCH and react appropriately (after scrolling is
enabled)
+* put yanked content (p)
+* turn screen into a lineset
+* change alloc/ensure functions to work on line_t* and lineset_t*
* add crop command (C)
* reorganise code
* change screen management (i.e., dynamic array of lines)
diff --git a/draw.c b/draw.c
@@ -299,9 +299,15 @@ void visual_box(FILE *fc){
draw_box(x,y,NOFIX);
while((c=fgetc(fc))!=EOF && c != 27 && c!= 'v' && c != '\n'){
if (!move_around(c, fc)) switch(c){
+ case 'y': /* yank (copy) */
+ yank_region(MIN(orig_x,x), MIN(orig_y,y), MAX(…
+ goto vis_exit;
+ break;
case 'f':/* fill */
f = get_key(fc, "fill char: "); /** FALLTHROUG…
case 'x':/* erase */
+ if (c == 'x')
+ yank_region(MIN(orig_x,x), MIN(orig_y,…
erase_box(orig_x, orig_y, f);
erase_blank_lines(MIN(y,orig_y), MAX(y, orig_y…
modified = 1;
@@ -323,3 +329,8 @@ vis_exit:
redraw();
mode = MOVE;
}
+
+void paste(){
+ paste_region(x, y);
+ redraw();
+}
diff --git a/files.c b/files.c
@@ -24,7 +24,7 @@ void write_file(FILE *fc){
return;
}
for (i=0; i<HEIGHT; i++){
- fprintf(fout, "%s\n", screen[i].s);
+ fprintf(fout, "%s\n", screen.l[i].s);
}
fclose(fout);
modified = 0;
@@ -50,8 +50,8 @@ void load_file(FILE *fc){
get_string(fc, "Load file: ", newfname, 255);
if ((fin=fopen(newfname, "r")) != NULL){
i = 0;
- while((fgets(screen[i].s, WIDTH+2, fin)) != NULL && i<HEIGHT)
- screen[i++].s[WIDTH-1]='\0';
+ while((fgets(screen.l[i].s, WIDTH+2, fin)) != NULL && i<HEIGHT)
+ screen.l[i++].s[WIDTH-1]='\0';
for(;i<HEIGHT; i++){
erase_line(i);
}
diff --git a/gramscii.1 b/gramscii.1
@@ -57,6 +57,12 @@ Crop chart to the largest non-blank region. The first line a…
column of the cropped chart will contain the first non-blank line and
the first non-blank column of the original chart, respectively.
.TP 5m
+.BI p
+Paste the content of the yank buffer at the cursor position. The yank
+buffer contains the rectangle yanked/cut in
+.B visual
+mode.
+.TP 5m
.BI q
Quit gramscii, and prompt for a filename if the current screen contains
unsaved changes.
@@ -340,9 +346,19 @@ commands to highlight a rectangle. Then, you can use one o…
following command on the highlighted region:
.RS
.TP 5m
+.BI y
+Yank (copy) the highlighted rectangle to the yank buffer. The content of
+the yank buffer can be retrieved by using the
+.B p
+command while in
+.B move
+mode. The yank buffer is overwritten by subsequent yank/cut commands.
+.TP 5m
.BI x
-Erase region. All the characters in the region are set to the default
-background character (space).
+Cut region. The content of the highlighted rectangle will be put in the
+yank buffer and all the characters in the region are set to the default
+background character (space). The yank buffer is overwritten by
+subsequent yank/cut commands.
.TP 5m
.BI f
Fill region. gramscii will wait for a character on input and then will
diff --git a/gramscii.h b/gramscii.h
@@ -5,13 +5,7 @@
#include <termios.h>
#include <unistd.h>
-/** types **/
-typedef struct{
- int sz;
- int lst;
- char *s;
-} line_t;
/** constants **/
@@ -50,6 +44,20 @@ typedef struct{
#define VIDEO_NRM 0
#define VIDEO_REV 7
+/** types **/
+
+typedef struct{
+ int sz;/* allocated size*/
+ int n;/* line number */
+ int lst;/* last visible char (before the first \0) */
+ char *s;
+} line_t;
+
+typedef struct{
+ int sz;/* allocated size */
+ int num;/* number of lines stored */
+ line_t *l;
+} lineset_t;
/** MACROS **/
@@ -63,8 +71,9 @@ typedef struct{
/** global variables **/
-line_t *screen;
-int num_lines;
+lineset_t screen;
+lineset_t cutbuf;
+
int WIDTH, HEIGHT;
int mode;
@@ -96,6 +105,7 @@ char visual;
char silent;
char autoend;
+
struct termios t1, t2, t3;
/** screen-related functions **/
@@ -129,6 +139,7 @@ void get_box(FILE *fc);
void get_arrow(FILE *fc);
void erase(FILE *fc);
void visual_box(FILE *fc);
+void paste();
/** file-related functions **/
void write_file(FILE *fc);
@@ -136,5 +147,14 @@ void check_modified(FILE *fc);
void load_file(FILE *fc);
void new_file(FILE *fc);
+/** line-related functions **/
+
+void dump_lines(lineset_t ls, FILE *f);
+void alloc_line(line_t *l);
+void ensure_line_length(line_t *l, int len);
+void ensure_num_lines(lineset_t *ls, int n);
+void yank_region(int x1, int y1, int x2, int y2);
+void paste_region(int x1, int y1);
+
#endif
diff --git a/lineset.c b/lineset.c
@@ -0,0 +1,117 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gramscii.h"
+
+static int LONG_STEP;
+
+/* line_t and lineset_t management */
+
+void ensure_line_length(line_t *l, int len){
+ char *tmp;
+
+ if (l->sz < len + 1){
+ tmp = realloc(l->s, (len+1) * 2 * sizeof(char));
+ if (!tmp){
+ fprintf(stderr, "Unable to allocate string\n");
+ exit(1);
+ }
+ l->s = tmp;
+ l->sz = (len + 1) * 2;
+ }
+}
+
+
+void alloc_line(line_t *l){
+ char *tmp;
+
+ l->sz = WIDTH+1;
+ tmp = malloc((l->sz) * sizeof(char));
+ if (tmp == NULL){
+ fprintf(stderr, "unable to allocate line\n");
+ exit(1);
+ }
+ l->s = tmp;
+ memset(l->s, BG, l->sz);
+ l->lst = -1;
+ l->s[0]='\0';
+}
+
+void ensure_num_lines(lineset_t *ls, int n){
+ line_t *tmp;
+
+ if (n > ls->sz){
+ if (ls->sz == 0)
+ ls->l=NULL;
+ tmp = realloc(ls->l, (n + LONG_STEP) * sizeof(line_t));
+ if (tmp == NULL){
+ fprintf(stderr, "Unable to allocate memory for more li…
+ exit(1);
+ }
+ else {
+ ls->l = tmp;
+ while ( ls->sz < n + LONG_STEP){
+ alloc_line(&(ls->l[ls->sz]));
+ ls->sz ++;
+ }
+ }
+ }
+}
+
+void dump_lines(lineset_t ls, FILE *f){
+ int i;
+ for (i=0; i<ls.num ;i++){
+ fprintf(f, "%d:%s\n", i, ls.l[i].s);
+ }
+ fflush(f);
+}
+
+void pad_line_to_length(char *s, int W){
+
+ int i;
+
+ for (i=strlen(s); i<W; i++){
+ s[i] = BG;
+ }
+}
+
+/* cut/yank/paste/undo management */
+
+void yank_region(int x1, int y1, int x2, int y2){
+
+ int N, W, i;
+
+ N = y2 - y1 + 1;
+ W = x2 - x1 + 1;
+ ensure_num_lines(&cutbuf, N);
+
+ for (i=y1; i<=y2; i++){
+ ensure_line_length(&(cutbuf.l[i-y1]), W);
+ memcpy(cutbuf.l[i-y1].s, screen.l[i].s + x1, x2-x1+1);
+ if (strlen(cutbuf.l[i-y1].s) < W)
+ pad_line_to_length(cutbuf.l[i-y1].s, W);
+ cutbuf.l[i-y1].s[W] = '\0';
+ cutbuf.l[i-y1].n = i;
+ }
+ cutbuf.num = N;
+#ifdef DEBUG
+ dump_lines(cutbuf, stderr);
+#endif
+
+}
+
+
+void paste_region(int x1, int y1){
+ int i, curlen;
+
+ i = y1;
+ while( i < HEIGHT && i < y1 + cutbuf.num){
+ memcpy(screen.l[i].s + x1, cutbuf.l[i-y1].s, strlen(cutbuf.l[i…
+ curlen = strlen(screen.l[i].s);
+ if (curlen <= x1)
+ /* double-check this line below */
+ pad_line_to_length(screen.l[i].s+curlen, x1 - curlen);
+ i += 1;
+ modified = 1;
+ }
+}
diff --git a/main.c b/main.c
@@ -30,19 +30,13 @@
char *argv0;
-void dump_lines(){
- int i;
- for (i=0; i<HEIGHT; i++){
- printf("%s\n", screen[i].s);
- }
-}
void cleanup(int s){
if (!silent)
printf("\033[;H\033[2J");
else
- dump_lines();
+ dump_lines(screen, stdout);
tcsetattr(0, TCSANOW, &t1);
fflush(stdout);
exit(0);
@@ -125,6 +119,9 @@ void commands(FILE *fc){
case 'C':
crop_to_nonblank();
break;
+ case 'p':
+ paste();
+ break;
case 'q':
check_modified(fc);/** FALLTHROUGH **/
case 'Q':
diff --git a/screen.c b/screen.c
@@ -1,9 +1,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <termios.h>
#include <sys/ioctl.h>
+#include <ctype.h>
#include "gramscii.h"
#include "config.h"
@@ -62,7 +62,7 @@ void status_bar(){
else
printf(" *%s*", fname );
#ifdef DEBUG
- printf(" '%d' ", screen[y].s[x]);
+ printf(" '%d' ", screen.l[y].s[x]);
#endif
printf("\033[0m");
fflush(stdout);
@@ -109,52 +109,6 @@ int is_yes(char c){
/*** Screen management ***/
-void ensure_line_length(int i, int len){
- char *tmp;
-
- if (screen[i].sz < len + 1){
- tmp = realloc(screen[i].s, (len+1) * 2 * sizeof(char));
- if (!tmp){
- fprintf(stderr, "Unable to allocate string\n");
- exit(1);
- }
- screen[i].s = tmp;
- screen[i].sz = (len + 1) * 2;
- }
-}
-
-
-void alloc_line(int i){
- char *tmp;
-
- screen[i].sz = WIDTH+1;
- tmp = malloc((screen[i].sz) * sizeof(char));
- if (tmp == NULL){
- fprintf(stderr, "unable to allocate line %d\n", i+1);
- exit(1);
- }
- screen[i].s = tmp;
- memset(screen[i].s, BG, screen[i].sz);
- screen[i].lst = -1;
- screen[i].s[0]='\0';
-}
-
-void ensure_num_lines(int n){
- line_t *tmp;
-
- if (n > num_lines){
- tmp = realloc(screen, (n + LONG_STEP) * sizeof(line_t));
- if (tmp == NULL){
- fprintf(stderr, "Unable to allocate memory for more li…
- exit(1);
- }
- else while ( num_lines < n + LONG_STEP){
- alloc_line(num_lines);
- num_lines ++;
- }
- }
-}
-
void show_cursor(){
if (silent)
@@ -165,15 +119,15 @@ void show_cursor(){
void set_xy(int _x, int _y, char c){
- ensure_num_lines(_y + 1);
- ensure_line_length(_y, _x + 1);
- while (screen[_y].lst<_x){
- screen[_y].lst ++;
- screen[_y].s[screen[_y].lst] = BG;
+ ensure_num_lines(&screen, _y + 1);
+ ensure_line_length(&(screen.l[_y]), _x + 1);
+ while (screen.l[_y].lst<_x){
+ screen.l[_y].lst ++;
+ screen.l[_y].s[screen.l[_y].lst] = BG;
}
- screen[_y].s[_x] = c;
- if (_x == screen[_y].lst)
- screen[_y].s[_x+1] = '\0';
+ screen.l[_y].s[_x] = c;
+ if (_x == screen.l[_y].lst)
+ screen.l[_y].s[_x+1] = '\0';
}
void set_cur(char c){
@@ -193,7 +147,7 @@ void update_current(){
if (silent)
return;
printf("\033[%d'%df",y+1,x+1);
- putchar(screen[y].s[x]);
+ putchar(screen.l[y].s[x]);
fflush(stdout);
}
@@ -206,20 +160,20 @@ void erase_blank_lines(int y1, int y2){
}
for (; y1 <= y2; y1++){
- j = screen[y1].lst;
- while (j>=0 && isblank(screen[y1].s[j]))
+ j = screen.l[y1].lst;
+ while (j>=0 && isblank(screen.l[y1].s[j]))
j--;
if (j<0){
- screen[y1].lst = -1;
- screen[y1].s[0] = '\0';
+ screen.l[y1].lst = -1;
+ screen.l[y1].s[0] = '\0';
}
}
}
void erase_line(int i){
- screen[i].lst = -1;
- screen[i].s[0] = '\0';
+ screen.l[i].lst = -1;
+ screen.l[i].s[0] = '\0';
}
void erase_box(int x1, int y1, char c){
@@ -268,7 +222,7 @@ void redraw(){
return;
printf("\033[2J\033[1;1H");
for (i=0;i<HEIGHT;i++){
- fprintf(stdout,"%s\n",screen[i].s);
+ fprintf(stdout,"%s\n",screen.l[i].s);
}
status_bar();
show_cursor();
@@ -435,14 +389,15 @@ void init_screen(){
WIDTH=80;
HEIGHT=24;
}
- screen = malloc(HEIGHT * sizeof(line_t));
- num_lines = HEIGHT;
- if (screen == NULL){
+ screen.l = malloc(HEIGHT * sizeof(line_t));
+ screen.sz = HEIGHT;
+ screen.num = HEIGHT;
+ if (screen.l == NULL){
perror("allocating screen");
exit(1);
}
for (i=0; i<HEIGHT; i++){
- alloc_line(i);
+ alloc_line(&(screen.l[i]));
}
hlines_sz= sizeof(hlines) -1;
vlines_sz= sizeof(vlines) -1;
@@ -450,6 +405,9 @@ void init_screen(){
stmarks_sz = sizeof(st_marks) - 1;
endmarks_sz = sizeof(st_marks) - 1;
reset_styles();
+ cutbuf.sz = 0;
+ cutbuf.l = NULL;
+ cutbuf.num = 0;
}
void find_nonblank_rect(int *x1, int *y1, int *x2, int *y2){
@@ -457,22 +415,22 @@ void find_nonblank_rect(int *x1, int *y1, int *x2, int *y…
int i, j;
int first;
*x1= WIDTH; /** FIXME: replace with num_cols **/
- *y1 = num_lines;
+ *y1 = screen.num;
*x2 = *y2 = 0;
- for (i=0; i<num_lines; i++){
- if (screen[i].lst < 0)
+ for (i=0; i<screen.num; i++){
+ if (screen.l[i].lst < 0)
continue;
*y2 = i;
if (i < *y1)
*y1 = i;
j = 0;
- while((j <= screen[i].lst) && isblank(first=screen[i].s[j]))
+ while((j <= screen.l[i].lst) && isblank(first=screen.l[i].s[j…
j++;
if (j < *x1)
*x1 = j;
- j = screen[i].lst;
- while(isblank(screen[i].s[j]))
+ j = screen.l[i].lst;
+ while(isblank(screen.l[i].s[j]))
j--;
if (j > *x2)
*x2 = j;
@@ -483,13 +441,13 @@ void crop_to_rect(int x1, int y1, int x2, int y2){
int i;
for (i=0; i<= y2-y1; i ++){
- ensure_line_length(i, screen[i+y1].lst);
- sprintf(screen[i].s, "%s", screen[i+y1].s + x1);
- screen[i].lst = screen[i+y1].lst - x1;
+ ensure_line_length(&(screen.l[i]), screen.l[i+y1].lst);
+ sprintf(screen.l[i].s, "%s", screen.l[i+y1].s + x1);
+ screen.l[i].lst = screen.l[i+y1].lst - x1;
}
while (i<=y2){
- screen[i].lst = -1;
- screen[i].s[0]= '\0';
+ screen.l[i].lst = -1;
+ screen.l[i].s[0]= '\0';
i ++;
}
}
@@ -505,3 +463,4 @@ void crop_to_nonblank(){
redraw();
}
+
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.