about summary refs log tree commit diff
path: root/pkgs/profpatsch/xdg-open/xdg-open.dhall
blob: 3edb31e5b0f5c7ff69d523c9ea74ae03b31ef964 (plain) (blame)
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
let Text/concatSep = ./imports/Prelude/Text/concatSep

let Text/concatMap = ./imports/Prelude/Text/concatMap

let List/concatMap = ./imports/Prelude/List/concatMap

let List/map = ./imports/Prelude/List/map

let
    -- TODO use library like with shell commands
    Executable =
      Text

let types = ./types.dhall

let renderMime = Text/concatSep "/"

let
    -- Escape the given shell command, at least the String arguments of it.
    -- Passes `$file` as variable argument.
    -- The final shell command is executed into.
    shellEscapeExecCommand =
      λ(shellEscape : Text → Text) →
      λ(file : Text) →
      λ(cmd : types.Command) →
          Text/concatSep
            " "
            (   [ "exec", shellEscape cmd.exe ]
              # List/map
                  types.Arg
                  Text
                  ( λ(arg : types.Arg) →
                      merge
                        { String = λ(t : Text) → shellEscape t
                        , Variable = λ(t : Text) → t
                        }
                        arg
                  )
                  (cmd.args (types.Arg.Variable file))
            )
        : Text

let repeatText =
      λ(t : Text) →
      λ(n : Natural) →
        Natural/fold n Text (λ(t2 : Text) → t ++ t2) ""

let Lines = { indent : Natural, lines : List Text }

let prettyLines =
      λ(lines : Lines) →
        Text/concatMap
          Text
          (λ(line : Text) → repeatText " " lines.indent ++ line ++ "\n")
          lines.lines

let xdg-open =
      let mimeMatcherCase =
            λ(shellEscape2 : Text → Text) →
            λ(file2 : Text) →
            λ(m : types.MimeMatch) →
              [ "${renderMime m.mime})"
              , "${shellEscapeExecCommand shellEscape2 file2 m.cmd}"
              , ";;"
              ]

      let mimeGlobCase =
            λ(shellEscape2 : Text → Text) →
            λ(file2 : Text) →
            λ(g : types.UriMimeGlob) →
                List/concatMap
                  Text
                  Text
                  ( λ(match : Text) →
                      [ "${match})"
                      , shellEscapeExecCommand shellEscape2 file2 g.handler.cmd
                      , ";;"
                      ]
                  )
                  g.glob
              : List Text

      in  λ(bins : { get-mime-type : Executable }) →
          λ(write-dash : Text → Text → Executable) →
          λ(shellEscape : Text → Text) →
          λ(pkgs : { package : Text, binary : Text } → Executable) →
          λ(special : types.Special) →
            let config = ./config.dhall pkgs special

            in  write-dash
                  "xdg-open"
                  (     ''

                        # partially taken from
                        # https://github.com/march-linux/mimi/blob/master/xdg-open

                        set -e
                        file="$1"
                        mime=

                        # TODO: --dry-run to display what would be opened and why
                        notify-send --expire-time=500 -- "xdg-open: $1"

                        # match on protocols
                        # if you want to match files reliably, start with file://
                        case "$file" in
                        ${prettyLines
                            { indent = 2
                            , lines =
                                List/concatMap
                                  types.UriMimeGlob
                                  Text
                                  (mimeGlobCase shellEscape "\"\$file\"")
                                  config.uriMimeGlobs
                            }}
                          *)
                            # it’s a file

                            # strip possible protocol
                            file=''
                    ++  "\$"
                    ++  ''
                        {file#file://}
                            mime=$(file -E --brief --mime-type "$file") \
                            || (echo "$mime" 1>&2; exit 1)
                            # ^ echo the error message of file
                            ;;
                        esac

                        case "$mime" in
                        ${prettyLines
                            { indent = 2
                            , lines =
                                List/concatMap
                                  types.MimeMatch
                                  Text
                                  (mimeMatcherCase shellEscape "\"\$file\"")
                                  config.orderedMimeMatchers
                            }}
                        esac
                        ''
                  )

in  xdg-open