about summary refs log tree commit diff
path: root/pkgs/profpatsch/xdg-open/xdg-open.dhall
blob: cd9e8d4cc889f135de6f253fb0de757ec785a230 (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
145
146
147
148
149
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 shellEscapeCommand =
      λ(shellEscape : Text → Text) →
      λ(file : Text) →
      λ(cmd : types.Command) →
          Text/concatSep
            " "
            (   [ 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})"
              , "${shellEscapeCommand shellEscape2 file2 m.cmd}"
              , ";;"
              ]

      let mimeGlobCase =
            λ(shellEscape2 : Text → Text) →
            λ(file2 : Text) →
            λ(g : types.UriMimeGlob) →
                List/concatMap
                  Text
                  Text
                  ( λ(match : Text) →
                      merge
                        { Mime =
                            λ(mime : types.Mime) →
                              [ "${match})", "mime=${renderMime mime}", ";;" ]
                        , Transparent =
                            λ(cmd : types.Command) →
                              [ "${match})"
                              , "mime=\"\$(${shellEscapeCommand
                                               shellEscape2
                                               file2
                                               cmd})\""
                              , ";;"
                              ]
                        }
                        g.handler
                  )
                  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"
                  (     ''
                        # TODO: --dry-run to display what would be opened and why

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

                        set -e
                        file="$1"
                        mime=

                        # 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