1 | #ifndef NVIM_CHANNEL_H |
2 | #define NVIM_CHANNEL_H |
3 | |
4 | #include "nvim/main.h" |
5 | #include "nvim/event/socket.h" |
6 | #include "nvim/event/process.h" |
7 | #include "nvim/os/pty_process.h" |
8 | #include "nvim/event/libuv_process.h" |
9 | #include "nvim/eval/typval.h" |
10 | #include "nvim/msgpack_rpc/channel_defs.h" |
11 | |
12 | #define CHAN_STDIO 1 |
13 | #define CHAN_STDERR 2 |
14 | |
15 | typedef enum { |
16 | kChannelStreamProc, |
17 | kChannelStreamSocket, |
18 | kChannelStreamStdio, |
19 | kChannelStreamStderr, |
20 | kChannelStreamInternal |
21 | } ChannelStreamType; |
22 | |
23 | typedef enum { |
24 | kChannelPartStdin, |
25 | kChannelPartStdout, |
26 | kChannelPartStderr, |
27 | kChannelPartRpc, |
28 | kChannelPartAll |
29 | } ChannelPart; |
30 | |
31 | |
32 | typedef struct { |
33 | Stream in; |
34 | Stream out; |
35 | } StdioPair; |
36 | |
37 | typedef struct { |
38 | bool closed; |
39 | } StderrState; |
40 | |
41 | typedef struct { |
42 | Callback cb; |
43 | dict_T *self; |
44 | garray_T buffer; |
45 | bool eof; |
46 | bool buffered; |
47 | const char *type; |
48 | } CallbackReader; |
49 | |
50 | #define CALLBACK_READER_INIT ((CallbackReader){ .cb = CALLBACK_NONE, \ |
51 | .self = NULL, \ |
52 | .buffer = GA_EMPTY_INIT_VALUE, \ |
53 | .buffered = false, \ |
54 | .type = NULL }) |
55 | static inline bool callback_reader_set(CallbackReader reader) |
56 | { |
57 | return reader.cb.type != kCallbackNone || reader.self; |
58 | } |
59 | |
60 | struct Channel { |
61 | uint64_t id; |
62 | size_t refcount; |
63 | MultiQueue *events; |
64 | |
65 | ChannelStreamType streamtype; |
66 | union { |
67 | Process proc; |
68 | LibuvProcess uv; |
69 | PtyProcess pty; |
70 | Stream socket; |
71 | StdioPair stdio; |
72 | StderrState err; |
73 | } stream; |
74 | |
75 | bool is_rpc; |
76 | RpcState rpc; |
77 | Terminal *term; |
78 | |
79 | CallbackReader on_data; |
80 | CallbackReader on_stderr; |
81 | Callback on_exit; |
82 | int exit_status; |
83 | |
84 | bool callback_busy; |
85 | bool callback_scheduled; |
86 | }; |
87 | |
88 | EXTERN PMap(uint64_t) *channels; |
89 | |
90 | #ifdef INCLUDE_GENERATED_DECLARATIONS |
91 | # include "channel.h.generated.h" |
92 | #endif |
93 | |
94 | /// @returns Channel with the id or NULL if not found |
95 | static inline Channel *find_channel(uint64_t id) |
96 | { |
97 | return pmap_get(uint64_t)(channels, id); |
98 | } |
99 | |
100 | static inline Stream *channel_instream(Channel *chan) |
101 | FUNC_ATTR_NONNULL_ALL |
102 | { |
103 | switch (chan->streamtype) { |
104 | case kChannelStreamProc: |
105 | return &chan->stream.proc.in; |
106 | |
107 | case kChannelStreamSocket: |
108 | return &chan->stream.socket; |
109 | |
110 | case kChannelStreamStdio: |
111 | return &chan->stream.stdio.out; |
112 | |
113 | case kChannelStreamInternal: |
114 | case kChannelStreamStderr: |
115 | abort(); |
116 | } |
117 | abort(); |
118 | } |
119 | |
120 | static inline Stream *channel_outstream(Channel *chan) |
121 | FUNC_ATTR_NONNULL_ALL |
122 | { |
123 | switch (chan->streamtype) { |
124 | case kChannelStreamProc: |
125 | return &chan->stream.proc.out; |
126 | |
127 | case kChannelStreamSocket: |
128 | return &chan->stream.socket; |
129 | |
130 | case kChannelStreamStdio: |
131 | return &chan->stream.stdio.in; |
132 | |
133 | case kChannelStreamInternal: |
134 | case kChannelStreamStderr: |
135 | abort(); |
136 | } |
137 | abort(); |
138 | } |
139 | |
140 | |
141 | #endif // NVIM_CHANNEL_H |
142 | |