Skip to content

Commit d295427

Browse files
committed
👍 Add decode() and append() function
Additionally, make `assign()` deprecated because developers can use `decode()` and `replace()` individually to get same result.
1 parent 083e6be commit d295427

File tree

3 files changed

+352
-30
lines changed

3 files changed

+352
-30
lines changed

denops_std/buffer/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,48 @@ export async function main(denops: Denops): Promise<void> {
7878
It may temporary change a current buffer or a current window to properly reload
7979
the content of the `bufnr` buffer.
8080

81+
### decode
82+
83+
Use `decode()` to decode raw binary content for string array for the `bufnr`
84+
buffer like:
85+
86+
```typescript
87+
import { Denops } from "../mod.ts";
88+
import * as fn from "../function/mod.ts";
89+
import { decode, open, replace } from "../buffer/mod.ts";
90+
91+
export async function main(denops: Denops): Promise<void> {
92+
await open(denops, "README.md");
93+
const bufnr = await fn.bufnr(denops) as number;
94+
const data = await Deno.readFile("README.md");
95+
const { content } = await decode(denops, bufnr, data);
96+
await replace(denops, bufnr, content);
97+
}
98+
```
99+
100+
It follows Vim's rule to find a corresponding `fileformat` and `fileencoding` to
101+
decode the `data` if the one is not given by `options`.
102+
103+
### append
104+
105+
Use `append()` to append the content of the `bufnr` buffer like:
106+
107+
```typescript
108+
import { Denops } from "../mod.ts";
109+
import * as fn from "../function/mod.ts";
110+
import { append, open } from "../buffer/mod.ts";
111+
112+
export async function main(denops: Denops): Promise<void> {
113+
await open(denops, "README.md");
114+
const bufnr = await fn.bufnr(denops) as number;
115+
// Append the content under the cursor position of the `bufnr` buffer
116+
await append(denops, bufnr, ["Hello", "World"]);
117+
}
118+
```
119+
120+
It temporary change `modified`, `modifiable`, and `foldmethod` options to append
121+
the content of the `buffer` buffer without unmodifiable error or so on.
122+
81123
### replace
82124

83125
Use `replace()` to replace the content of the `bufnr` buffer like:
@@ -100,6 +142,8 @@ replace the content of the `buffer` buffer without unmodifiable error or so on.
100142

101143
### assign
102144

145+
**DEPRECATED: Use `decode()` and `replace()` individually**
146+
103147
Use `assign()` to assign raw binary content into the `bufnr` buffer like:
104148

105149
```typescript

denops_std/buffer/buffer.ts

Lines changed: 100 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { execute } from "../helper/mod.ts";
66
import * as unknownutil from "https://deno.land/x/unknownutil@v2.0.0/mod.ts";
77
import {
88
assertFileFormat,
9+
FileFormat,
910
findFileFormat,
1011
isFileFormat,
1112
maybeFileFormat,
@@ -54,6 +55,18 @@ async function ensurePrerequisites(denops: Denops): Promise<string> {
5455
endtry
5556
endfunction
5657
58+
function! DenopsStdBufferAppend_${suffix}(bufnr, lnum, repl) abort
59+
let modified = getbufvar(a:bufnr, '&modified')
60+
let modifiable = getbufvar(a:bufnr, '&modifiable')
61+
let foldmethod = getbufvar(a:bufnr, '&foldmethod')
62+
call setbufvar(a:bufnr, '&modifiable', 1)
63+
call setbufvar(a:bufnr, '&foldmethod', 'manual')
64+
call appendbufline(a:bufnr, a:lnum, a:repl)
65+
call setbufvar(a:bufnr, '&modified', modified)
66+
call setbufvar(a:bufnr, '&modifiable', modifiable)
67+
call setbufvar(a:bufnr, '&foldmethod', foldmethod)
68+
endfunction
69+
5770
function! DenopsStdBufferReplace_${suffix}(bufnr, repl, fileformat, fileencoding) abort
5871
let modified = getbufvar(a:bufnr, '&modified')
5972
let modifiable = getbufvar(a:bufnr, '&modifiable')
@@ -142,6 +155,82 @@ export async function reload(denops: Denops, bufnr: number): Promise<void> {
142155
);
143156
}
144157

158+
/**
159+
* Decode content for the buffer with given format and encoding.
160+
*/
161+
export async function decode(
162+
denops: Denops,
163+
bufnr: number,
164+
data: Uint8Array,
165+
options: DecodeOptions = {},
166+
): Promise<DecodeResult> {
167+
const [fileformat, fileformatsStr, fileencodingsStr] = await batch.gather(
168+
denops,
169+
async (denops) => {
170+
await fn.getbufvar(denops, bufnr, "&fileformat");
171+
await fn.getbufvar(denops, bufnr, "&fileformats");
172+
await fn.getbufvar(denops, bufnr, "&fileencodings");
173+
},
174+
);
175+
assertFileFormat(fileformat);
176+
unknownutil.assertString(fileformatsStr);
177+
unknownutil.assertString(fileencodingsStr);
178+
const fileformats = fileformatsStr.split(",");
179+
const fileencodings = fileencodingsStr.split(",");
180+
unknownutil.assertArray(fileformats, isFileFormat);
181+
unknownutil.assertArray(fileencodings, unknownutil.isString);
182+
let enc: string;
183+
let text: string;
184+
if (options.fileencoding) {
185+
enc = options.fileencoding;
186+
text = (new TextDecoder(enc)).decode(data);
187+
} else {
188+
[enc, text] = tryDecode(data, fileencodings);
189+
}
190+
const ff = maybeFileFormat(options.fileformat) ??
191+
findFileFormat(text, fileformats) ?? fileformat;
192+
return {
193+
content: splitText(text, ff),
194+
fileformat: ff,
195+
fileencoding: enc,
196+
};
197+
}
198+
199+
export type DecodeOptions = {
200+
fileformat?: string;
201+
fileencoding?: string;
202+
};
203+
204+
export type DecodeResult = {
205+
content: string[];
206+
fileformat: FileFormat;
207+
fileencoding: string;
208+
};
209+
210+
/**
211+
* Append content under the current cursor position or given lnum of the buffer
212+
*/
213+
export async function append(
214+
denops: Denops,
215+
bufnr: number,
216+
repl: string[],
217+
options: AppendOptions = {},
218+
): Promise<void> {
219+
const suffix = await ensurePrerequisites(denops);
220+
const lnum = options.lnum ??
221+
await ensure(denops, bufnr, () => fn.line(denops, "."));
222+
await denops.call(
223+
`DenopsStdBufferAppend_${suffix}`,
224+
bufnr,
225+
lnum,
226+
repl,
227+
);
228+
}
229+
230+
export type AppendOptions = {
231+
lnum?: number;
232+
};
233+
145234
/**
146235
* Replace the buffer content
147236
*/
@@ -168,49 +257,30 @@ export type ReplaceOptions = {
168257

169258
/**
170259
* Assign content to the buffer with given format and encoding.
260+
*
261+
* @deprecated Use `decode()` and `replace()` individually instead.
171262
*/
172263
export async function assign(
173264
denops: Denops,
174265
bufnr: number,
175-
content: Uint8Array,
266+
data: Uint8Array,
176267
options: AssignOptions = {},
177268
): Promise<void> {
178-
const [fileformat, fileformatsStr, fileencodingsStr] = await batch.gather(
269+
const { content, fileformat, fileencoding } = await decode(
179270
denops,
180-
async (denops) => {
181-
await fn.getbufvar(denops, bufnr, "&fileformat");
182-
await fn.getbufvar(denops, bufnr, "&fileformats");
183-
await fn.getbufvar(denops, bufnr, "&fileencodings");
184-
},
271+
bufnr,
272+
data,
273+
options,
185274
);
186-
assertFileFormat(fileformat);
187-
unknownutil.assertString(fileformatsStr);
188-
unknownutil.assertString(fileencodingsStr);
189-
const fileformats = fileformatsStr.split(",");
190-
const fileencodings = fileencodingsStr.split(",");
191-
unknownutil.assertArray(fileformats, isFileFormat);
192-
unknownutil.assertArray(fileencodings, unknownutil.isString);
193-
let enc: string;
194-
let text: string;
195-
if (options.fileencoding) {
196-
enc = options.fileencoding;
197-
text = (new TextDecoder(enc)).decode(content);
198-
} else {
199-
[enc, text] = tryDecode(content, fileencodings);
200-
}
201-
const ff = maybeFileFormat(options.fileformat) ??
202-
findFileFormat(text, fileformats) ?? fileformat;
203275
const preprocessor = options.preprocessor ?? ((v: string[]) => v);
204-
const repl = preprocessor(splitText(text, ff));
276+
const repl = preprocessor(content);
205277
await replace(denops, bufnr, repl, {
206-
fileformat: ff,
207-
fileencoding: enc,
278+
fileformat,
279+
fileencoding,
208280
});
209281
}
210282

211-
export type AssignOptions = {
212-
fileformat?: string;
213-
fileencoding?: string;
283+
export type AssignOptions = DecodeOptions & {
214284
preprocessor?: (repl: string[]) => string[];
215285
};
216286

0 commit comments

Comments
 (0)