Skip to content

Commit 217fdc2

Browse files
authored
Merge pull request #6 from hawkkiller/feat/custom-wrap-with
Custom wrap with
2 parents 5441345 + 1d158af commit 217fdc2

File tree

8 files changed

+174
-106
lines changed

8 files changed

+174
-106
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,34 @@ This package extends your Flutter development experience by providing convenient
88

99
Simply select the widget you want to wrap, and choose the appropriate "Wrap with..." command from the command palette, or use the provided snippets to quickly insert the desired wrapper code into your widget tree.
1010

11-
- **Wrap with SizedBox**: Surround your widget with a `SizedBox` to provide constraints on its size, such as width, height, or aspect ratio.
11+
This extension includes the following standard "Wrap with..." commands:
12+
1213
- **Wrap with ListenableBuilder**: Easily wrap any widget with a `ListenableBuilder` to rebuild the widget based on changes in a `Listenable` object.
1314
- **Wrap with ValueListenableBuilder<T>**: Automatically wrap your widget with a `ValueListenableBuilder` to react to changes in a `ValueListenable<T>`.
1415
- **Wrap with RepaintBoundary**: Encapsulate your widget within a `RepaintBoundary` to isolate its repaint process, improving performance in complex UIs.
16+
- **Wrap with SliverPadding**: Wrap your widget with a `SliverPadding` to add padding around a sliver widget in a `CustomScrollView`.
17+
18+
In order to add custom "Wrap with" commands, you can change the configuration in `flutter-plus.wraps` settings. The configuration is an array of objects with the following properties:
19+
20+
- **name**: The name of the command that will appear in the command palette.
21+
- **body**: The snippet body that will be inserted into the editor when the command is executed. Use `${0...N}` to indicate the position of the selected text. In order to insert the selected text, use `${widget}`.
22+
23+
Example configuration:
1524

25+
```json
26+
{
27+
"wraps": [
28+
{
29+
"name": "Wrap with CustomWidget",
30+
"body": [
31+
"CustomWidget(",
32+
" child: ${widget},",
33+
")"
34+
]
35+
}
36+
]
37+
}
38+
```
1639

1740
## Markdown snippets
1841

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,6 @@
6565
"command": "flutter-plus.sealed-states",
6666
"title": "Create Sealed States",
6767
"category": "Flutter Plus"
68-
},
69-
{
70-
"command": "flutter-plus.wrap-sizedbox",
71-
"title": "Wrap with SizedBox",
72-
"category": "Flutter Plus"
73-
},
74-
{
75-
"command": "flutter-plus.wrap-listenablebuilder",
76-
"title": "Wrap with ListenableBuilder",
77-
"category": "Flutter Plus"
78-
},
79-
{
80-
"command": "flutter-plus.wrap-valuelistenablebuilder",
81-
"title": "Wrap with ValueListenableBuilder<T>",
82-
"category": "Flutter Plus"
83-
},
84-
{
85-
"command": "flutter-plus.wrap-repaintboundary",
86-
"title": "Wrap with RepaintBoundary",
87-
"category": "Flutter Plus"
8868
}
8969
],
9070
"views": {
@@ -132,7 +112,69 @@
132112
"language": "dart",
133113
"path": "./snippets/flutter.json"
134114
}
135-
]
115+
],
116+
"configuration": {
117+
"title": "Wraps",
118+
"properties": {
119+
"flutter-plus.wraps": {
120+
"description": "Set up custom Wrap With here",
121+
"type": "array",
122+
"items": {
123+
"type": "object",
124+
"properties": {
125+
"name": {
126+
"type": "string",
127+
"description": "Name of the Widget"
128+
},
129+
"body": {
130+
"type": "array",
131+
"items": {
132+
"type": "string"
133+
},
134+
"description": "Body of the Widget, use $ for cursor position and ${widget} for selected text"
135+
}
136+
}
137+
},
138+
"default": [
139+
{
140+
"name": "ListenableBuilder",
141+
"body": [
142+
"ListenableBuilder(",
143+
" listenable: ${1:listenable},",
144+
" builder: (context, _) => ${widget},",
145+
")"
146+
]
147+
},
148+
{
149+
"name": "ValueListenableBuilder",
150+
"body": [
151+
"ValueListenableBuilder(",
152+
" valueListenable: ${1:valueListenable},",
153+
" builder: (context, value, _) => ${widget},",
154+
")"
155+
]
156+
},
157+
{
158+
"name": "RepaintBoundary",
159+
"body": [
160+
"RepaintBoundary(",
161+
" child: ${widget},",
162+
")"
163+
]
164+
},
165+
{
166+
"name": "SliverPadding",
167+
"body": [
168+
"SliverPadding(",
169+
" padding: const EdgeInsets.all(${1:8.0}),",
170+
" sliver: ${widget},",
171+
")"
172+
]
173+
}
174+
]
175+
}
176+
}
177+
}
136178
},
137179
"extensionDependencies": [
138180
"Dart-Code.dart-code",

src/code-actions/code-action-wrap.ts

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,26 @@
22

33
import { CodeAction, CodeActionKind, CodeActionProvider, window } from "vscode";
44
import { getSelectedText } from "../utils";
5+
import { CodeWrap } from "../extension";
56

67
export class CodeActionWrap implements CodeActionProvider {
8+
private wraps: Array<CodeWrap>;
9+
10+
constructor(customWraps: Array<CodeWrap>) {
11+
this.wraps = customWraps;
12+
}
13+
714
public provideCodeActions(): CodeAction[] {
815
const editor = window.activeTextEditor;
916
if (!editor) return [];
1017

1118
const selectedText = editor.document.getText(getSelectedText(editor));
1219
if (selectedText === "") return [];
1320

14-
return [
15-
{
16-
command: "flutter-plus.wrap-sizedbox",
17-
title: "Wrap with SizedBox",
18-
},
19-
{
20-
command: "flutter-plus.wrap-listenablebuilder",
21-
title: "Wrap with ListenableBuilder",
22-
},
23-
{
24-
command: "flutter-plus.wrap-valuelistenablebuilder",
25-
title: "Wrap with ValueListenableBuilder<T>",
26-
},
27-
/* TODO: Convert between ListenableBuilder <--> ValueListenableBuilder */
28-
{
29-
command: "flutter-plus.wrap-repaintboundary",
30-
title: "Wrap with RepaintBoundary",
31-
}
32-
].map((c) => {
21+
return this.wraps.map((c) => {
3322
let action = new CodeAction(c.title, CodeActionKind.Refactor);
3423
action.command = {
35-
command: c.command,
24+
command: c.commandId,
3625
title: c.title,
3726
};
3827
return action;

src/commands/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
11
export * from "./sealed-states.command";
2-
3-
export * from "./wrap-with.command";

src/commands/wrap-with.command.ts

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/config/config.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { workspace } from "vscode";
2+
3+
export type CustomWrapConfig = {
4+
name: string,
5+
body: Array<string>,
6+
};
7+
8+
export class FlutterPlusConfig {
9+
private static instance: FlutterPlusConfig;
10+
11+
public static getInstance(): FlutterPlusConfig {
12+
if (!FlutterPlusConfig.instance) {
13+
FlutterPlusConfig.instance = new FlutterPlusConfig();
14+
}
15+
return FlutterPlusConfig.instance;
16+
}
17+
18+
public getCustomWraps(): Array<CustomWrapConfig> {
19+
const config = workspace.getConfiguration('flutter-plus');
20+
const customWraps = config.get<Array<CustomWrapConfig>>('wraps');
21+
22+
return customWraps || [];
23+
}
24+
}

src/extension.ts

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import * as vscode from 'vscode';
22

33
import {
4-
sealedStates,
5-
wrapWithListenableBuilder,
6-
wrapWithRepaintBoundary,
7-
wrapWithSizedBox,
8-
wrapWithValueListenableBuilder,
9-
} from "./commands";
4+
Disposable
5+
} from "vscode";
106

117
import {
12-
CodeActionWrap,
13-
} from './code-actions';
8+
sealedStates
9+
} from "./commands";
10+
11+
import { FlutterPlusConfig } from './config/config';
12+
import { wrapWith } from './utils';
1413

1514

1615
import {
@@ -21,6 +20,7 @@ import {
2120
/* import fs from 'fs';
2221
import path from 'path'; */
2322

23+
import { CodeActionWrap } from './code-actions';
2424
import {
2525
SdkCommands,
2626
} from './utils';
@@ -63,9 +63,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
6363
/// Register all commands.
6464
function registerCommands(context: vscode.ExtensionContext) {
6565
context.subscriptions.push(
66-
/* vscode.commands.registerCommand('flutter-plus.helloWorld', () => {
67-
vscode.window.showInformationMessage('Hello World from Flutter Plus!');
68-
}), */
6966
vscode.commands.registerCommand("flutter-plus.sealed-states", sealedStates),
7067
);
7168
}
@@ -88,16 +85,52 @@ function registerCommands(context: vscode.ExtensionContext) {
8885

8986
/// Register all wrappers (Wrap With...).
9087
function registerWrappers(context: vscode.ExtensionContext) {
88+
var wraps = $registerWrappers(context);
89+
const disposable = vscode.workspace.onDidChangeConfiguration(event => {
90+
if (!event.affectsConfiguration('flutter-plus')) {
91+
return;
92+
}
93+
94+
$unregisterWrappers(wraps);
95+
wraps = $registerWrappers(context);
96+
});
97+
98+
context.subscriptions.push(disposable);
99+
}
100+
101+
function $unregisterWrappers(disposables: Array<Disposable>) {
102+
disposables.forEach((disposable) => disposable.dispose());
103+
}
104+
105+
function $registerWrappers(context: vscode.ExtensionContext): Array<Disposable> {
106+
const configWraps = FlutterPlusConfig.getInstance().getCustomWraps();
107+
const wraps: Array<CodeWrap> = configWraps.map((wrap) => {
108+
return {
109+
commandId: "flutter-plus.wrapWith." + wrap.name.toLowerCase().replace(/\s/g, "-"),
110+
title: "Wrap with " + wrap.name,
111+
command: () => wrapWith((selectedText) => wrap.body.join("\n").replace("\${widget}", selectedText)),
112+
};
113+
});
114+
115+
const subscriptions = [
116+
...wraps.map((wrap) => {
117+
return vscode.commands.registerCommand(wrap.commandId, wrap.command);
118+
}),
119+
vscode.languages.registerCodeActionsProvider(DART_MODE, new CodeActionWrap(wraps)),
120+
];
121+
91122
context.subscriptions.push(
92-
vscode.commands.registerCommand("flutter-plus.wrap-sizedbox", wrapWithSizedBox),
93-
vscode.commands.registerCommand("flutter-plus.wrap-listenablebuilder", wrapWithListenableBuilder),
94-
vscode.commands.registerCommand("flutter-plus.wrap-valuelistenablebuilder", wrapWithValueListenableBuilder),
95-
vscode.commands.registerCommand("flutter-plus.wrap-repaintboundary", wrapWithRepaintBoundary),
96-
vscode.languages.registerCodeActionsProvider(
97-
DART_MODE,
98-
new CodeActionWrap(),
99-
),
123+
...subscriptions,
100124
);
125+
126+
return subscriptions;
101127
}
102128

129+
103130
export function deactivate() { }
131+
132+
export type CodeWrap = {
133+
commandId: string,
134+
title: string,
135+
command: () => void,
136+
};

0 commit comments

Comments
 (0)