Browse Source

Add start of X clipboard support

via xclip. Using popen instead of pipes right now, so stderr from
xclip might be sent to terminal, which is bad.
master
cancel 5 years ago
parent
commit
23329f713a
  1. 21
      base.h
  2. 48
      cboard.c
  3. 15
      cboard.h
  4. 2
      tool
  5. 81
      tui_main.c

21
base.h

@ -92,3 +92,24 @@ ORCA_FORCE_STATIC_INLINE Usz orca_round_up_power2(Usz x) {
#endif #endif
return x + 1; return x + 1;
} }
ORCA_OK_IF_UNUSED
static bool is_valid_glyph(Glyph c) {
if (c >= '0' && c <= '9')
return true;
if (c >= 'A' && c <= 'Z')
return true;
if (c >= 'a' && c <= 'z')
return true;
switch (c) {
case '!':
case '.':
case '*':
case ':':
case ';':
case '=':
case '#':
return true;
}
return false;
}

48
cboard.c

@ -0,0 +1,48 @@
#include "cboard.h"
#include "gbuffer.h"
#include <stdio.h>
Cboard_error cboard_copy(Glyph const* gbuffer, Usz field_height,
Usz field_width, Usz rect_y, Usz rect_x, Usz rect_h,
Usz rect_w) {
(void)field_height;
FILE* fp = popen("xclip -i -selection clipboard", "w");
if (!fp)
return Cboard_error_popen_failed;
for (Usz iy = 0; iy < rect_h; iy++) {
Glyph const* row = gbuffer + (rect_y + iy) * field_width + rect_x;
for (Usz ix = 0; ix < rect_w; ix++) {
fputc(row[ix], fp);
}
if (iy < rect_h + 1)
fputc('\n', fp);
}
int status = pclose(fp);
return status ? Cboard_error_process_exit_error : Cboard_error_none;
}
Cboard_error cboard_paste(Glyph* gbuffer, Usz height, Usz width, Usz y, Usz x) {
FILE* fp = popen("xclip -o -selection clipboard", "r");
Usz start_x = x;
if (!fp)
return Cboard_error_popen_failed;
for (;;) {
int c = fgetc(fp);
if (c == EOF)
break;
if (c == '\r' || c == '\n') {
y++;
x = start_x;
continue;
}
if (c != ' ' && y < height && x < width) {
Glyph g = c <= CHAR_MAX && c >= CHAR_MIN && is_valid_glyph((Glyph)c)
? (Glyph)c
: '.';
gbuffer_poke(gbuffer, height, width, y, x, g);
}
x++;
}
int status = pclose(fp);
return status ? Cboard_error_process_exit_error : Cboard_error_none;
}

15
cboard.h

@ -0,0 +1,15 @@
#pragma once
#include "base.h"
typedef enum {
Cboard_error_none = 0,
Cboard_error_unavailable,
Cboard_error_popen_failed,
Cboard_error_process_exit_error,
} Cboard_error;
Cboard_error cboard_copy(Glyph const* gbuffer, Usz field_height,
Usz field_width, Usz rect_y, Usz rect_x, Usz rect_h,
Usz rect_w);
Cboard_error cboard_paste(Glyph* gbuffer, Usz height, Usz width, Usz y, Usz x);

2
tool

@ -293,7 +293,7 @@ build_target() {
out_exe=cli out_exe=cli
;; ;;
orca|tui) orca|tui)
add source_files osc_out.c term_util.c tui_main.c add source_files osc_out.c term_util.c cboard.c tui_main.c
add cc_flags -D_XOPEN_SOURCE_EXTENDED=1 add cc_flags -D_XOPEN_SOURCE_EXTENDED=1
# thirdparty headers (like sokol_time.h) should get -isystem for their # thirdparty headers (like sokol_time.h) should get -isystem for their
# include dir so that any warnings they generate with our warning flags # include dir so that any warnings they generate with our warning flags

81
tui_main.c

@ -1,5 +1,6 @@
#include "bank.h" #include "bank.h"
#include "base.h" #include "base.h"
#include "cboard.h"
#include "field.h" #include "field.h"
#include "gbuffer.h" #include "gbuffer.h"
#include "osc_out.h" #include "osc_out.h"
@ -119,26 +120,6 @@ static Glyph_class glyph_class_of(Glyph glyph) {
return Glyph_class_unknown; return Glyph_class_unknown;
} }
static bool is_valid_glyph(Glyph c) {
if (c >= '0' && c <= '9')
return true;
if (c >= 'A' && c <= 'Z')
return true;
if (c >= 'a' && c <= 'z')
return true;
switch (c) {
case '!':
case '.':
case '*':
case ':':
case ';':
case '=':
case '#':
return true;
}
return false;
}
static attr_t term_attrs_of_cell(Glyph g, Mark m) { static attr_t term_attrs_of_cell(Glyph g, Mark m) {
Glyph_class gclass = glyph_class_of(g); Glyph_class gclass = glyph_class_of(g);
attr_t attr = A_normal; attr_t attr = A_normal;
@ -2182,6 +2163,36 @@ Bracketed_paste_sequence bracketed_paste_sequence_getch_ungetch(WINDOW* win) {
return Bracketed_paste_sequence_none; return Bracketed_paste_sequence_none;
} }
void try_send_to_gui_clipboard(Ged const* a, bool* io_use_gui_clipboard) {
if (!*io_use_gui_clipboard)
return;
// If we want to use grid directly
#if 0
Usz curs_y, curs_x, curs_h, curs_w;
if (!ged_try_selection_clipped_to_field(a, &curs_y, &curs_x, &curs_h,
&curs_w))
return;
Cboard_error cberr =
cboard_copy(a->clipboard_field.buffer, a->clipboard_field.height,
a->clipboard_field.width, curs_y, curs_x, curs_h, curs_w);
#endif
Usz cb_h = a->clipboard_field.height, cb_w = a->clipboard_field.width;
if (cb_h < 1 || cb_w < 1)
return;
Cboard_error cberr =
cboard_copy(a->clipboard_field.buffer, cb_h, cb_w, 0, 0, cb_h, cb_w);
if (cberr) {
*io_use_gui_clipboard = false;
switch (cberr) {
case Cboard_error_none:
case Cboard_error_unavailable:
case Cboard_error_popen_failed:
case Cboard_error_process_exit_error:
break;
}
}
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
static struct option tui_options[] = { static struct option tui_options[] = {
{"margins", required_argument, 0, Argopt_margins}, {"margins", required_argument, 0, Argopt_margins},
@ -2211,6 +2222,7 @@ int main(int argc, char** argv) {
bool should_autosize_grid = true; bool should_autosize_grid = true;
int init_grid_dim_y = 25; int init_grid_dim_y = 25;
int init_grid_dim_x = 57; int init_grid_dim_x = 57;
bool use_gui_cboard = true;
Midi_mode midi_mode; Midi_mode midi_mode;
midi_mode_init_null(&midi_mode); midi_mode_init_null(&midi_mode);
@ -2969,12 +2981,39 @@ int main(int argc, char** argv) {
break; break;
case CTRL_PLUS('x'): case CTRL_PLUS('x'):
ged_input_cmd(&ged_state, Ged_input_cmd_cut); ged_input_cmd(&ged_state, Ged_input_cmd_cut);
try_send_to_gui_clipboard(&ged_state, &use_gui_cboard);
break; break;
case CTRL_PLUS('c'): case CTRL_PLUS('c'):
ged_input_cmd(&ged_state, Ged_input_cmd_copy); ged_input_cmd(&ged_state, Ged_input_cmd_copy);
try_send_to_gui_clipboard(&ged_state, &use_gui_cboard);
break; break;
case CTRL_PLUS('v'): case CTRL_PLUS('v'):
ged_input_cmd(&ged_state, Ged_input_cmd_paste); if (use_gui_cboard) {
undo_history_push(&ged_state.undo_hist, &ged_state.field,
ged_state.tick_num);
Cboard_error cberr =
cboard_paste(ged_state.field.buffer, ged_state.field.height,
ged_state.field.width, ged_state.ged_cursor.y,
ged_state.ged_cursor.x);
if (cberr) {
undo_history_pop(&ged_state.undo_hist, &ged_state.field,
&ged_state.tick_num);
switch (cberr) {
case Cboard_error_none:
break;
case Cboard_error_unavailable:
case Cboard_error_popen_failed:
case Cboard_error_process_exit_error:
break;
}
use_gui_cboard = false;
ged_input_cmd(&ged_state, Ged_input_cmd_paste);
}
ged_state.needs_remarking = true;
ged_state.is_draw_dirty = true;
} else {
ged_input_cmd(&ged_state, Ged_input_cmd_paste);
}
break; break;
case '\'': case '\'':
ged_input_cmd(&ged_state, Ged_input_cmd_toggle_selresize_mode); ged_input_cmd(&ged_state, Ged_input_cmd_toggle_selresize_mode);

Loading…
Cancel
Save