aboutsummaryrefslogtreecommitdiff
path: root/rxvt/.urxvt/ext/selection-to-clipboard
blob: 0431694d7db8faaa441597fd6bf93f6ba622e78c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#! perl -w

=head1 NAME

selection-to-clipboard - copy the selection to the clipboard each time a selection is made

=head1 SYNOPSIS

   urxvt -pe selection-to-clipboard

=head1 DESCRIPTION

This very simple extension copies the selection to the clipboard every
time a selection is made. This, in effect, synchronises the clipboard with
the selection for selections done by rxvt-unicode.

=cut

sub on_sel_grab {
   my ($self, $time) = @_;

   $self->selection ($self->selection, 1);
   $self->selection_grab ($time, 1);

   ()
}
ighlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
open StdLabels
module A = ImportAnalyser.Dependency
module C = ImportContainers
module CSV = ImportCSV
module Syntax = ImportConf.Syntax
module Db = ImportSQL.Db

let flags = Unix.[ O_RDONLY; O_NONBLOCK ]

let extractors =
  SZXX.Xlsx.
    {
      string = (fun _location s -> CSV.DataType.Content s);
      error =
        (fun _location s -> CSV.DataType.Error (Printf.sprintf "#ERROR# %s" s));
      boolean =
        (fun _location s ->
          let value = String.(equal s "1") in
          CSV.DataType.Content (string_of_bool value));
      number =
        (fun _location s ->
          let f = Float.of_string s in
          if Float.is_integer f then CSV.DataType.Integer (Float.to_int f)
          else CSV.DataType.Float f);
      date = (fun _location s -> CSV.DataType.Content s);
      null = CSV.DataType.Null;
      formula =
        (fun _location ~formula s ->
          ignore formula;
          CSV.DataType.Content s);
    }

let feed_bigstring ic =
  let open Lwt.Infix in
  let len = Lwt_io.buffer_size ic in
  let buf = Lwt_bytes.create len in
  SZXX.Zip.Bigstring
    (fun () ->
      Lwt_io.read_into_bigstring ic buf 0 len >|= function
      | 0 -> None
      | len -> Some SZXX.Zip.{ buf; pos = 0; len })

(* Evaluate if the row can be processed right now (does not contain
   any delayed value) *)
let is_delayed row =
  Array.exists row.SZXX.Xlsx.data ~f:(function
    | SZXX.Xlsx.Delayed _ -> true
    | _ -> false)

let default_mapper :
    (ImportCSV.DataType.t, ImportCSV.DataType.t SZXX.Xlsx.row) State.mapper =
  {
    get_value =
      (function
      | ImportCSV.DataType.Content s ->
          ImportCSV.DataType.Content (SZXX.Xml.unescape s)
      | any -> any);
    default = ImportCSV.DataType.Null;
    get_row = (fun v -> v.SZXX.Xlsx.data);
  }

type state = CSV.DataType.t SZXX.Xlsx.status SZXX.Xlsx.row State.t

let delayed_mapper =
  State.
    {
      get_value =
        (function
        | SZXX.Xlsx.Available (CSV.DataType.Content s) ->
            CSV.DataType.Content (SZXX.Xml.unescape s)
        | SZXX.Xlsx.Available value -> value
        | _ -> CSV.DataType.Null);
      default = SZXX.Xlsx.Available CSV.DataType.Null;
      get_row = (fun v -> v.SZXX.Xlsx.data);
    }

(** Initialize the state for the first row, count the column number and create
    the table in the database *)
let first_row : A.t -> _ Db.t -> state -> 'a SZXX.Xlsx.row -> state =
 fun mapping db acc row ->
  (if acc.transaction then
     match Db.commit db with
     | Ok () -> ()
     | Error e -> print_endline (ImportErrors.repr_error e));

  ignore @@ Db.create_table db mapping;
  match Db.prepare_insert db mapping with
  | Ok stmt ->
      {
        acc with
        header = Some row;
        transaction = false;
        insert_stmt = Some stmt;
      }
  | _ -> { acc with header = Some row; transaction = false; insert_stmt = None }

let importInDatable :
    log_error:Csv.out_channel Lazy.t ->
    conf:Syntax.t ->
    dirname:string ->
    A.t ->
    'a Db.t ->
    CSV.DataType.t array option Lwt.t =
 fun ~log_error ~conf ~dirname mapping db ->
  let file = Filename.concat dirname (A.table mapping).file in

  Lwt_io.with_file ~flags ~mode:Input file (fun ic ->
      let open Lwt.Syntax in
      let stream, sst_p, success =
        SZXX.Xlsx.stream_rows ~only_sheet:(A.table mapping).tab
          ~feed:(feed_bigstring ic) extractors
      in
      let* processed =
        Lwt_stream.fold
          (fun row acc ->
            (* Create the table on the first line *)
            if Int.equal 1 row.SZXX.Xlsx.row_number then
              first_row mapping db acc row
            else
              match is_delayed row with
              | true -> { acc with delayed = row :: acc.delayed }
              | false -> (
                  let row_number = row.SZXX.Xlsx.row_number in
                  if acc.transaction then
                    State.run_row ~log_error ~mapper:delayed_mapper mapping db
                      row { acc with row_number }
                  else
                    match Db.begin_transaction db with
                    | Error e ->
                        print_endline (ImportErrors.repr_error e);
                        acc
                    | Ok () ->
                        let acc = { acc with transaction = true; row_number } in
                        State.run_row ~log_error ~mapper:delayed_mapper mapping
                          db row acc))
          stream
          {
            transaction = false;
            header = None;
            delayed = [];
            insert_stmt = None;
            check_key_stmt = None;
            row_number = 1;
            sheet_number = (A.table mapping).tab;
          }
      in
      (* Wait to reach the sst *)
      let* sst = sst_p in

      if processed.transaction then ignore (Db.commit db);

      (* Insert the missing elements *)
      ignore @@ Db.begin_transaction db;
      List.iter processed.delayed ~f:(fun row ->
          let fully_available_row =
            SZXX.Xlsx.unwrap_status extractors sst row
          in

          let row_number = row.SZXX.Xlsx.row_number in

          match
            State.insert_row ~mapper:default_mapper mapping db
              fully_available_row
              { processed with row_number }
          with
          | Ok _ -> ()
          | Error e ->
              ImportErrors.output_error log_error e;
              ());

      ignore @@ State.clear ~log_error db mapping conf;
      ignore @@ Db.commit db;

      (* Finalize the statements created during the import  *)
      let () =
        Option.iter (fun v -> ignore @@ Db.finalize v) processed.insert_stmt;
        Option.iter (fun v -> ignore @@ Db.finalize v) processed.check_key_stmt
      in

      let _ =
        Option.iter
          (fun headers ->
            let res = SZXX.Xlsx.unwrap_status extractors sst headers in

            let values = Array.mapi res.data ~f:(fun i value -> (i, value)) in

            ignore
            @@ Db.insert_header db
                 (ImportAnalyser.Dependency.table mapping)
                 values)
          processed.header
      in

      let header =
        Option.map
          (fun header ->
            let res = SZXX.Xlsx.unwrap_status extractors sst header in
            res.data)
          processed.header
      in

      (* Finalize the process *)
      let* () = success in

      Lwt.return header)