From: malc Date: Sat, 1 Jun 2013 17:54:36 +0000 (+0400) Subject: pax wip X-Git-Tag: v16~30 X-Git-Url: https://repo.or.cz/w/llpp.git/commitdiff_plain/9e528136fd55592e32aeaaefbc09b4c8c5c15095 pax wip --- diff --git a/KEYS b/KEYS index 6b00438..f782921 100644 --- a/KEYS +++ b/KEYS @@ -41,6 +41,7 @@ e - view error log m - create named bookmark ~ - create quick bookmark z - crop +x - run pax command on pointed region r - reload document [5] P - "presentation" mode a - autoscroll @@ -86,6 +87,7 @@ tunables -t - set thumbnail width (pixels) -T - toggle trimming of margins -I - invert colors +-M - toggle pax mode -C - set column count -x - set command to run on selection -f - toggle "what's under cursor" identification diff --git a/link.c b/link.c index c797dbf..fd06079 100644 --- a/link.c +++ b/link.c @@ -2946,6 +2946,159 @@ CAMLprim value ml_whatsunder (value ptr_v, value x_v, value y_v) CAMLreturn (ret_v); } +enum { mark_page, mark_block, mark_line, mark_word }; + +static int white (int c) +{ + return c == ' ' || c == '\n' || c == '\t' || c == '\n' || c == '\r'; +} + +CAMLprim value ml_markunder (value ptr_v, value x_v, value y_v, value mark_v) +{ + CAMLparam4 (ptr_v, x_v, y_v, mark_v); + CAMLlocal3 (ret_v, tup_v, str_v); + fz_rect *b; + struct page *page; + fz_text_line *line; + fz_page_block *pageb; + fz_text_block *block; + struct pagedim *pdim; + int mark = Int_val (mark_v); + char *s = String_val (ptr_v); + int x = Int_val (x_v), y = Int_val (y_v); + + ret_v = Val_bool (0); + if (trylock ("ml_markunder")) { + goto done; + } + + page = parse_pointer ("ml_markunder", s); + pdim = &state.pagedims[page->pdimno]; + x += pdim->bounds.x0; + y += pdim->bounds.y0; + + ensuretext (page); + + if (mark == mark_page) { + int i; + + for (i = page->text->len - 1; i >= 0; --i) { + pageb = &page->text->blocks[i]; + if (pageb->type != FZ_PAGE_BLOCK_TEXT) continue; + } + if (i < 0) goto unlock; + + block = pageb->u.text; + + page->fmark.i = 0; + page->fmark.span = block->lines->first_span; + + line = &block->lines[block->len - 1]; + page->lmark.i = line->last_span->len - 1; + page->lmark.span = line->last_span; + ret_v = Val_bool (1); + goto unlock; + } + + for (pageb = page->text->blocks; + pageb < page->text->blocks + page->text->len; + ++pageb) { + if (pageb->type != FZ_PAGE_BLOCK_TEXT) continue; + block = pageb->u.text; + + b = &block->bbox; + if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1)) + continue; + + if (mark == mark_block) { + page->fmark.i = 0; + page->fmark.span = block->lines->first_span; + + line = &block->lines[block->len - 1]; + page->lmark.i = line->last_span->len - 1; + page->lmark.span = line->last_span; + ret_v = Val_bool (1); + goto unlock; + } + + for (line = block->lines; + line < block->lines + block->len; + ++line) { + fz_text_span *span; + + b = &line->bbox; + if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1)) + continue; + + if (mark == mark_line) { + page->fmark.i = 0; + page->fmark.span = line->first_span; + + page->lmark.i = line->last_span->len - 1; + page->lmark.span = line->last_span; + ret_v = Val_bool (1); + goto unlock; + } + + for (span = line->first_span; span; span = span->next) { + int charnum; + + b = &span->bbox; + if (!(x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1)) + continue; + + for (charnum = 0; charnum < span->len; ++charnum) { + fz_rect bbox; + fz_text_char_bbox (&bbox, span, charnum); + b = &bbox; + + if (x >= b->x0 && x <= b->x1 && y >= b->y0 && y <= b->y1) { + /* unicode ftw */ + int charnum2, charnum3 = -1, charnum4 = -1; + + if (white (span->text[charnum].c)) goto unlock; + + for (charnum2 = charnum; charnum2 >= 0; --charnum2) { + if (white (span->text[charnum2].c)) { + charnum3 = charnum2 + 1; + break; + } + } + if (charnum3 == -1) charnum3 = 0; + + for (charnum2 = charnum + 1; + charnum2 < span->len; + ++charnum2) { + if (white (span->text[charnum2].c)) break; + charnum4 = charnum2; + } + if (charnum4 == -1) goto unlock; + + page->fmark.i = charnum3; + page->fmark.span = span; + + page->lmark.i = charnum4; + page->lmark.span = span; + ret_v = Val_bool (1); + goto unlock; + } + } + } + } + } + unlock: + unlock ("ml_markunder"); + + done: + if (!Bool_val (ret_v)) { + page->fmark.span = NULL; + page->lmark.span = NULL; + page->fmark.i = 0; + page->lmark.i = 0; + } + CAMLreturn (ret_v); +} + CAMLprim value ml_seltext (value ptr_v, value rect_v) { CAMLparam2 (ptr_v, rect_v); @@ -3156,9 +3309,9 @@ CAMLprim value ml_popen (value command_v, value fds_v) } #endif -CAMLprim value ml_copysel (value fd_v, value ptr_v) +CAMLprim value ml_copysel (value fd_v, value ptr_v, value clear_v) { - CAMLparam1 (ptr_v); + CAMLparam3 (fd_v, ptr_v, clear_v); FILE *f; int seen = 0; struct page *page; @@ -3167,6 +3320,7 @@ CAMLprim value ml_copysel (value fd_v, value ptr_v) fz_text_block *block; int fd = Int_val (fd_v); char *s = String_val (ptr_v); + int clear = Bool_val (clear_v); if (trylock ("ml_copysel")) { goto done; @@ -3223,8 +3377,10 @@ CAMLprim value ml_copysel (value fd_v, value ptr_v) } } endloop: - page->lmark.span = NULL; - page->fmark.span = NULL; + if (clear) { + page->lmark.span = NULL; + page->fmark.span = NULL; + } close: if (f != stdout) { diff --git a/main.ml b/main.ml index 9caec02..c4a873f 100644 --- a/main.ml +++ b/main.ml @@ -13,6 +13,13 @@ type under = | Uremote of (string * int) and facename = string;; +type mark = + | Mark_page + | Mark_block + | Mark_line + | Mark_word +;; + type params = (angle * fitmodel * trimparams * texcount * sliceheight * memsize * colorspace * fontpath * trimcachepath @@ -86,9 +93,10 @@ type pipe = (Unix.file_descr * Unix.file_descr);; external init : pipe -> params -> unit = "ml_init";; external seltext : string -> (int * int * int * int) -> unit = "ml_seltext";; -external copysel : Unix.file_descr -> opaque -> unit = "ml_copysel";; +external copysel : Unix.file_descr -> opaque -> bool -> unit = "ml_copysel";; external getpdimrect : int -> float array = "ml_getpdimrect";; external whatsunder : string -> int -> int -> under = "ml_whatsunder";; +external markunder : string -> int -> int -> mark -> bool = "ml_markunder";; external zoomforh : int -> int -> int -> int -> float = "ml_zoom_for_height";; external drawstr : int -> int -> int -> string -> float = "ml_draw_string";; external measurestr : int -> string -> float = "ml_measure_string";; @@ -345,6 +353,7 @@ type conf = ; mutable columns : columns ; mutable beyecolumns : columncount option ; mutable selcmd : string + ; mutable paxcmd : string ; mutable updatecurs : bool ; mutable keyhashes : (string * keyhash) list ; mutable hfsize : int @@ -353,6 +362,8 @@ type conf = ; mutable wheelbypage : bool ; mutable stcmd : string ; mutable riani : bool + ; mutable pax : (float * int * int) ref option + ; mutable paxmark : mark } and columns = | Csingle of singlecolumn @@ -487,6 +498,7 @@ type state = ; mutable winh : int ; mutable reprf : (unit -> unit) ; mutable origin : string + ; mutable roam : (unit -> unit) } and hists = { pat : string circbuf @@ -550,6 +562,7 @@ let defconf = | Posx -> "pbcopy" | Pcygwin -> "wsel" | Punknown -> "cat") + ; paxcmd = "cat" ; colorspace = Rgb ; invert = false ; colorscale = 1.0 @@ -564,6 +577,8 @@ let defconf = ; wheelbypage = false ; stcmd = "echo SyncTex" ; riani = false + ; pax = None + ; paxmark = Mark_word ; keyhashes = let mk n = (n, Hashtbl.create 1) in [ mk "global" @@ -729,6 +744,7 @@ let state = ; winh = -1 ; reprf = noreprf ; origin = "" + ; roam = (fun () -> ()) } ;; @@ -918,6 +934,44 @@ let showtext c s = G.postRedisplay "showtext"; ;; +let paxunder x y = + let g opaque l px py = + if markunder opaque px py conf.paxmark + then ( + Some (fun () -> + match getopaque l.pageno with + | None -> () + | Some opaque -> + match Ne.pipe () with + | Ne.Exn exn -> + showtext '!' + (Printf.sprintf + "can not create mark pipe: %s" + (exntos exn)); + | Ne.Res (r, w) -> + let doclose what fd = + Ne.clo fd (fun msg -> + dolog "%s close failed: %s" what msg) + in + try + popen conf.paxcmd [r, 0; w, -1]; + copysel w opaque false; + doclose "pipe/r" r; + G.postRedisplay "paxunder"; + with exn -> + dolog "can not execute %S: %s" + conf.paxcmd (exntos exn); + doclose "pipe/r" r; + doclose "pipe/w" w; + ) + ) + else None + in + G.postRedisplay "paxunder"; + state.roam <- + onppundermouse g x y (fun () -> showtext '!' "Whoopsie daisy"); +;; + let selstring s = match Ne.pipe () with | Ne.Exn exn -> @@ -1043,6 +1097,37 @@ let colorspace_to_string = function | Gray -> "gray" ;; +let mark_of_string s = + match String.lowercase s with + | "word" -> Mark_word + | "line" -> Mark_line + | "block" -> Mark_block + | "page" -> Mark_page + | _ -> failwith "invalid colorspace" +;; + +let int_of_mark = function + | Mark_page -> 0 + | Mark_block -> 1 + | Mark_line -> 2 + | Mark_word -> 3 +;; + +let mark_of_int = function + | 0 -> Mark_page + | 1 -> Mark_block + | 2 -> Mark_line + | 3 -> Mark_word + | n -> failwith ("invalid mark index " ^ string_of_int n) +;; + +let mark_to_string = function + | Mark_word -> "word" + | Mark_line -> "line" + | Mark_block -> "block" + | Mark_page -> "page" +;; + let fitmodel_of_string s = match String.lowercase s with | "width" -> FitWidth @@ -3156,6 +3241,12 @@ let optentry mode _ key = TEswitch ("selection command: ", "", Some (onhist state.hists.sel), textentry, ondone, true) + | 'M' -> + if conf.pax == None + then conf.pax <- Some (ref (0.0, 0, 0)) + else conf.pax <- None; + TEdone ("PAX " ^ btos (conf.pax != None)) + | _ -> state.text <- Printf.sprintf "bad option %d `%c'" key c; TEstop @@ -4321,6 +4412,33 @@ let enterinfomode = coe (new listview ~source ~trusted:true ~modehash) )) :: m_l + method roammark name get set = + m_l <- + (name, `string get, 1, Action ( + fun _ -> + let source = + let vals = [| "page"; "block"; "line"; "word" |] in + (object + inherit lvsourcebase + + initializer + m_active <- int_of_mark conf.paxmark; + m_first <- 0; + + method getitemcount = Array.length vals + method getitem n = (vals.(n), 0) + method exit ~uioh ~cancel ~active ~first ~pan ~qsearch = + ignore (uioh, first, pan, qsearch); + if not cancel then set active; + None + method hasaction _ = true + end) + in + state.text <- ""; + let modehash = findkeyhash conf "info" in + coe (new listview ~source ~trusted:true ~modehash) + )) :: m_l + method fitmodel name get set = m_l <- (name, `string get, 1, Action ( @@ -4592,6 +4710,12 @@ let enterinfomode = src#bool "redirect stderr" (fun () -> conf.redirectstderr) (fun v -> conf.redirectstderr <- v; redirectstderr ()); + src#bool "pax mode" + (fun () -> conf.pax != None) + (fun v -> + if v + then conf.pax <- Some (ref (now (), 0, 0)) + else conf.pax <- None); src#string "uri launcher" (fun () -> conf.urilauncher) (fun v -> conf.urilauncher <- v); @@ -4706,6 +4830,9 @@ let enterinfomode = src#string "synctex command" (fun () -> conf.stcmd) (fun v -> conf.stcmd <- v); + src#string "pax command" + (fun () -> conf.paxcmd) + (fun v -> conf.paxcmd <- v); src#colorspace "color space" (fun () -> colorspace_to_string conf.colorspace) (fun v -> @@ -4713,6 +4840,9 @@ let enterinfomode = wcmd "cs %d" v; load state.layout; ); + src#roammark "pax mark method" + (fun () -> mark_to_string conf.paxmark) + (fun v -> conf.paxmark <- mark_of_int v); if pbousable () then src#bool "use PBO" @@ -5157,7 +5287,7 @@ let viewkeyboard key mask = | 45 | 0xffad -> (* - *) let ondone msg = state.text <- msg in enttext ( - "option [acfhilpstvxACFPRSZTIS]: ", "", None, + "option [acfhilpstvxACFPRSZTISM]: ", "", None, optentry state.mode, ondone, true ) @@ -5364,6 +5494,7 @@ let viewkeyboard key mask = | [] -> () end + | 120 -> state.roam () | 60 | 62 -> (* < > *) reqlayout (conf.angle + (if key = 62 then 30 else -30)) conf.fitmodel @@ -5484,10 +5615,10 @@ let viewkeyboard key mask = gotoghyll (clamp state.maxy) | 0xff53 | 0xff98 - when Wsi.withalt mask -> (* alt-(kp) right *) + when Wsi.withalt mask -> (* alt-(kp) right *) gotoghyll (getnav 1) | 0xff51 | 0xff96 - when Wsi.withalt mask -> (* alt-(kp) left *) + when Wsi.withalt mask -> (* alt-(kp) left *) gotoghyll (getnav ~-1) | 114 -> (* r *) @@ -6107,7 +6238,7 @@ let viewmouse button down x y mask = in try popen conf.selcmd [r, 0; w, -1]; - copysel w opaque; + copysel w opaque true; doclose "pipe/r" r; G.postRedisplay "copysel"; with exn -> @@ -6240,9 +6371,19 @@ let uioh = object | LinkNav _ | View -> match state.mstate with - | Mnone -> updateunder x y | Mpan _ | Msel _ | Mzoom _ | Mscrolly | Mscrollx | Mzoomrect _ -> () + | Mnone -> + updateunder x y; + match conf.pax with + | None -> () + | Some r -> + let past, _, _ = !r in + let now = now () in + let delta = now -. past in + if delta > 0.01 + then paxunder x y + else r := (now, x, y) end; state.uioh @@ -6430,6 +6571,7 @@ struct { c with beyecolumns = Some (max (int_of_string v) 2) } | "selection-command" -> { c with selcmd = unent v } | "synctex-command" -> { c with stcmd = unent v } + | "pax-command" -> { c with paxcmd = unent v } | "update-cursor" -> { c with updatecurs = bool_of_string v } | "hint-font-size" -> { c with hfsize = bound (int_of_string v) 5 100 } | "page-scroll-scale" -> { c with pgscale = float_of_string v } @@ -6450,6 +6592,11 @@ struct in { c with scrollb = b } | "remote-in-a-new-instance" -> { c with riani = bool_of_string v } + | "point-and-x" -> + { c with pax = + if bool_of_string v + then Some (ref (0.0, 0, 0)) + else None } | _ -> c with exn -> prerr_endline ("Error processing attribute (`" ^ @@ -6562,8 +6709,13 @@ struct dst.usepbo <- src.usepbo; dst.wheelbypage <- src.wheelbypage; dst.stcmd <- src.stcmd; + dst.paxcmd <- src.paxcmd; dst.scrollb <- src.scrollb; dst.riani <- src.riani; + dst.pax <- + if src.pax = None + then None + else Some ((ref (0.0, 0, 0))); ;; let get s = @@ -6858,6 +7010,9 @@ struct let ob s a b = if always || a != b then Printf.bprintf bb "\n %s='%b'" s a + and op s a b = + if always || a <> b + then Printf.bprintf bb "\n %s='%b'" s (a != None) and oi s a b = if always || a != b then Printf.bprintf bb "\n %s='%d'" s a @@ -6975,6 +7130,7 @@ struct obeco "birds-eye-columns" c.beyecolumns dc.beyecolumns; os "selection-command" c.selcmd dc.selcmd; os "synctex-command" c.stcmd dc.stcmd; + os "pax-command" c.paxcmd dc.paxcmd; ob "update-cursor" c.updatecurs dc.updatecurs; oi "hint-font-size" c.hfsize dc.hfsize; oi "horizontal-scroll-step" c.hscrollstep dc.hscrollstep; @@ -6982,6 +7138,7 @@ struct ob "use-pbo" c.usepbo dc.usepbo; ob "wheel-scrolls-pages" c.wheelbypage dc.wheelbypage; ob "remote-in-a-new-instance" c.riani dc.riani; + op "point-and-x" c.pax dc.pax; ;; let keymapsbuf always dc c =