Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0db119d

Browse files
#919, #881: Fixed 3rd party URLs-related issues (#920)
* Fixed empty string to URLs conversion Closes #919. Signed-off-by: Akos Kitta <kittaakos@gmail.com> * #881: Fixed height of the 3rd part URLs `textarea` Closes #881. Signed-off-by: Akos Kitta <kittaakos@gmail.com>
1 parent c9b498f commit 0db119d

File tree

7 files changed

+159
-31
lines changed

7 files changed

+159
-31
lines changed

‎arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx‎

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { WindowService } from '@theia/core/lib/browser/window/window-service';
99
import { FileDialogService } from '@theia/filesystem/lib/browser/file-dialog/file-dialog-service';
1010
import { DisposableCollection } from '@theia/core/lib/common/disposable';
1111
import {
12+
AdditionalUrls,
1213
CompilerWarningLiterals,
1314
Network,
1415
ProxySettings,
@@ -35,21 +36,32 @@ export class SettingsComponent extends React.Component<
3536
if (
3637
this.state &&
3738
prevState &&
38-
JSON.stringify(this.state) !== JSON.stringify(prevState)
39+
JSON.stringify(SettingsComponent.State.toSettings(this.state)) !==
40+
JSON.stringify(SettingsComponent.State.toSettings(prevState))
3941
) {
40-
this.props.settingsService.update(this.state, true);
42+
this.props.settingsService.update(
43+
SettingsComponent.State.toSettings(this.state),
44+
true
45+
);
4146
}
4247
}
4348

4449
componentDidMount(): void {
4550
this.props.settingsService
4651
.settings()
47-
.then((settings) => this.setState(settings));
48-
this.toDispose.push(
52+
.then((settings) =>
53+
this.setState(SettingsComponent.State.fromSettings(settings))
54+
);
55+
this.toDispose.pushAll([
4956
this.props.settingsService.onDidChange((settings) =>
50-
this.setState(settings)
51-
)
52-
);
57+
this.setState((prevState) => ({
58+
...SettingsComponent.State.merge(prevState, settings),
59+
}))
60+
),
61+
this.props.settingsService.onDidReset((settings) =>
62+
this.setState(SettingsComponent.State.fromSettings(settings))
63+
),
64+
]);
5365
}
5466

5567
componentWillUnmount(): void {
@@ -290,8 +302,8 @@ export class SettingsComponent extends React.Component<
290302
<input
291303
className="theia-input stretch with-margin"
292304
type="text"
293-
value={this.state.additionalUrls.join(',')}
294-
onChange={this.additionalUrlsDidChange}
305+
value={this.state.rawAdditionalUrlsValue}
306+
onChange={this.rawAdditionalUrlsValueDidChange}
295307
/>
296308
<i
297309
className="fa fa-window-restore theia-button shrink"
@@ -475,11 +487,13 @@ export class SettingsComponent extends React.Component<
475487

476488
protected editAdditionalUrlDidClick = async (): Promise<void> => {
477489
const additionalUrls = await new AdditionalUrlsDialog(
478-
this.state.additionalUrls,
490+
AdditionalUrls.parse(this.state.rawAdditionalUrlsValue,','),
479491
this.props.windowService
480492
).open();
481493
if (additionalUrls) {
482-
this.setState({ additionalUrls });
494+
this.setState({
495+
rawAdditionalUrlsValue: AdditionalUrls.stringify(additionalUrls),
496+
});
483497
}
484498
};
485499

@@ -492,11 +506,11 @@ export class SettingsComponent extends React.Component<
492506
}
493507
};
494508

495-
protected additionalUrlsDidChange = (
509+
protected rawAdditionalUrlsValueDidChange = (
496510
event: React.ChangeEvent<HTMLInputElement>
497511
): void => {
498512
this.setState({
499-
additionalUrls: event.target.value.split(',').map((url)=>url.trim()),
513+
rawAdditionalUrlsValue: event.target.value,
500514
});
501515
};
502516

@@ -699,5 +713,48 @@ export namespace SettingsComponent {
699713
readonly windowService: WindowService;
700714
readonly localizationProvider: AsyncLocalizationProvider;
701715
}
702-
export type State = Settings & { languages: string[] };
716+
export type State = Settings & {
717+
rawAdditionalUrlsValue: string;
718+
};
719+
export namespace State {
720+
export function fromSettings(settings: Settings): State {
721+
return {
722+
...settings,
723+
rawAdditionalUrlsValue: AdditionalUrls.stringify(
724+
settings.additionalUrls
725+
),
726+
};
727+
}
728+
export function toSettings(state: State): Settings {
729+
const parsedAdditionalUrls = AdditionalUrls.parse(
730+
state.rawAdditionalUrlsValue,
731+
','
732+
);
733+
return {
734+
...state,
735+
additionalUrls: AdditionalUrls.sameAs(
736+
state.additionalUrls,
737+
parsedAdditionalUrls
738+
)
739+
? state.additionalUrls
740+
: parsedAdditionalUrls,
741+
};
742+
}
743+
export function merge(prevState: State, settings: Settings): State {
744+
const prevAdditionalUrls = AdditionalUrls.parse(
745+
prevState.rawAdditionalUrlsValue,
746+
','
747+
);
748+
return {
749+
...settings,
750+
rawAdditionalUrlsValue: prevState.rawAdditionalUrlsValue,
751+
additionalUrls: AdditionalUrls.sameAs(
752+
prevAdditionalUrls,
753+
settings.additionalUrls
754+
)
755+
? prevAdditionalUrls
756+
: settings.additionalUrls,
757+
};
758+
}
759+
}
703760
}

‎arduino-ide-extension/src/browser/dialogs/settings/settings-dialog.tsx‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { FileDialogService } from '@theia/filesystem/lib/browser/file-dialog/fil
1111
import { nls } from '@theia/core/lib/common';
1212
import { SettingsComponent } from './settings-component';
1313
import { AsyncLocalizationProvider } from '@theia/core/lib/common/i18n/localization';
14+
import { AdditionalUrls } from '../../../common/protocol';
1415

1516
@injectable()
1617
export class SettingsWidget extends ReactWidget {
@@ -96,7 +97,7 @@ export class SettingsDialog extends AbstractDialog<Promise<Settings>> {
9697
this.update();
9798
}
9899

99-
protected onUpdateRequest(msg: Message) {
100+
protected onUpdateRequest(msg: Message): void {
100101
super.onUpdateRequest(msg);
101102
this.widget.update();
102103
}
@@ -105,7 +106,7 @@ export class SettingsDialog extends AbstractDialog<Promise<Settings>> {
105106
super.onActivateRequest(msg);
106107

107108
// calling settingsService.reset() in order to reload the settings from the preferenceService
108-
// and update the UI including changes triggerd from the command palette
109+
// and update the UI including changes triggered from the command palette
109110
this.settingsService.reset();
110111

111112
this.widget.activate();
@@ -168,10 +169,7 @@ export class AdditionalUrlsDialog extends AbstractDialog<string[]> {
168169
}
169170

170171
get value(): string[] {
171-
return this.textArea.value
172-
.split('\n')
173-
.map((url) => url.trim())
174-
.filter((url) => !!url);
172+
return AdditionalUrls.parse(this.textArea.value, 'newline');
175173
}
176174

177175
protected onAfterAttach(message: Message): void {

‎arduino-ide-extension/src/browser/dialogs/settings/settings.tsx‎

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import { ThemeService } from '@theia/core/lib/browser/theming';
88
import { MaybePromise } from '@theia/core/lib/common/types';
99
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
1010
import { PreferenceService, PreferenceScope } from '@theia/core/lib/browser';
11-
import { Index } from '../../../common/types';
1211
import {
12+
AdditionalUrls,
1313
CompilerWarnings,
1414
ConfigService,
1515
FileSystemExt,
@@ -35,7 +35,7 @@ export const UPLOAD_VERBOSE_SETTING = `${UPLOAD_SETTING}.verbose`;
3535
export const UPLOAD_VERIFY_SETTING = `${UPLOAD_SETTING}.verify`;
3636
export const SHOW_ALL_FILES_SETTING = `${SKETCHBOOK_SETTING}.showAllFiles`;
3737

38-
export interface Settings extendsIndex{
38+
export interface Settings {
3939
editorFontSize: number; // `editor.fontSize`
4040
themeId: string; // `workbench.colorTheme`
4141
autoSave: 'on' | 'off'; // `editor.autoSave`
@@ -53,7 +53,7 @@ export interface Settings extends Index {
5353
sketchbookShowAllFiles: boolean; // `arduino.sketchbook.showAllFiles`
5454

5555
sketchbookPath: string; // CLI
56-
additionalUrls: string[]; // CLI
56+
additionalUrls: AdditionalUrls; // CLI
5757
network: Network; // CLI
5858
}
5959
export namespace Settings {
@@ -84,6 +84,8 @@ export class SettingsService {
8484

8585
protected readonly onDidChangeEmitter = new Emitter<Readonly<Settings>>();
8686
readonly onDidChange = this.onDidChangeEmitter.event;
87+
protected readonly onDidResetEmitter = new Emitter<Readonly<Settings>>();
88+
readonly onDidReset = this.onDidResetEmitter.event;
8789

8890
protected ready = new Deferred<void>();
8991
protected _settings: Settings;
@@ -167,7 +169,10 @@ export class SettingsService {
167169
async update(settings: Settings, fireDidChange = false): Promise<void> {
168170
await this.ready.promise;
169171
for (const key of Object.keys(settings)) {
170-
this._settings[key] = settings[key];
172+
if (key in this._settings) {
173+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
174+
(this._settings as any)[key] = (settings as any)[key];
175+
}
171176
}
172177
if (fireDidChange) {
173178
this.onDidChangeEmitter.fire(this._settings);
@@ -176,7 +181,8 @@ export class SettingsService {
176181

177182
async reset(): Promise<void> {
178183
const settings = await this.loadSettings();
179-
return this.update(settings, true);
184+
await this.update(settings, false);
185+
this.onDidResetEmitter.fire(this._settings);
180186
}
181187

182188
async validate(
@@ -267,7 +273,10 @@ export class SettingsService {
267273

268274
// after saving all the settings, if we need to change the language we need to perform a reload
269275
// Only reload if the language differs from the current locale. `nls.locale === undefined` signals english as well
270-
if (currentLanguage !== nls.locale && !(currentLanguage === 'en' && nls.locale === undefined)) {
276+
if (
277+
currentLanguage !== nls.locale &&
278+
!(currentLanguage === 'en' && nls.locale === undefined)
279+
) {
271280
if (currentLanguage === 'en') {
272281
window.localStorage.removeItem(nls.localeId);
273282
} else {

‎arduino-ide-extension/src/browser/style/settings-dialog.css‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,7 @@
5757
display: flex;
5858
justify-content: center;
5959
}
60+
61+
.p-Widget.dialogOverlay .dialogBlock .dialogContent.additional-urls-dialog {
62+
display: block;
63+
}

‎arduino-ide-extension/src/common/protocol/config-service.ts‎

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export interface Config {
116116
readonly sketchDirUri: string;
117117
readonly dataDirUri: string;
118118
readonly downloadsDirUri: string;
119-
readonly additionalUrls: string[];
119+
readonly additionalUrls: AdditionalUrls;
120120
readonly network: Network;
121121
readonly daemon: Daemon;
122122
}
@@ -141,3 +141,32 @@ export namespace Config {
141141
);
142142
}
143143
}
144+
export type AdditionalUrls = string[];
145+
export namespace AdditionalUrls {
146+
export function parse(value: string, delimiter: ',' | 'newline'): string[] {
147+
return value
148+
.trim()
149+
.split(delimiter === ',' ? delimiter : /\r?\n/)
150+
.map((url) => url.trim())
151+
.filter((url) => !!url);
152+
}
153+
export function stringify(additionalUrls: AdditionalUrls): string {
154+
return additionalUrls.join(',');
155+
}
156+
export function sameAs(left: AdditionalUrls, right: AdditionalUrls): boolean {
157+
if (left.length !== right.length) {
158+
return false;
159+
}
160+
const localeCompare = (left: string, right: string) =>
161+
left.localeCompare(right);
162+
const normalize = (url: string) => url.toLowerCase();
163+
const normalizedLeft = left.map(normalize).sort(localeCompare);
164+
const normalizedRight = right.map(normalize).sort(localeCompare);
165+
for (let i = 0; i < normalizedLeft.length; i++) {
166+
if (normalizedLeft[i] !== normalizedRight[i]) {
167+
return false;
168+
}
169+
}
170+
return true;
171+
}
172+
}
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
11
export type RecursiveRequired<T> = {
22
[P in keyof T]-?: RecursiveRequired<T[P]>;
33
};
4-
5-
export interface Index {
6-
[key: string]: any;
7-
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { expect } from 'chai';
2+
import { AdditionalUrls } from '../../common/protocol';
3+
4+
describe('config-service', () => {
5+
describe('additionalUrls', () => {
6+
it('should consider additional URLs same as if they differ in case', () => {
7+
expect(AdditionalUrls.sameAs(['aaaa'], ['AAAA'])).to.be.true;
8+
});
9+
it('should consider additional URLs same as if they have a different order', () => {
10+
expect(AdditionalUrls.sameAs(['bbbb', 'aaaa'], ['aaaa', 'bbbb'])).to.be
11+
.true;
12+
});
13+
it('should parse an empty string as an empty array', () => {
14+
expect(AdditionalUrls.parse('', ',')).to.be.empty;
15+
});
16+
it('should parse a blank string as an empty array', () => {
17+
expect(AdditionalUrls.parse(' ', ',')).to.be.empty;
18+
});
19+
it('should parse urls with commas', () => {
20+
expect(AdditionalUrls.parse(' ,a , b , c, ', ',')).to.be.deep.equal([
21+
'a',
22+
'b',
23+
'c',
24+
]);
25+
});
26+
it("should parse urls with both '\\n' and '\\r\\n' line endings", () => {
27+
expect(
28+
AdditionalUrls.parse(
29+
'a ' + '\r\n' + ' b ' + '\n' + ' c ' + '\r\n' + ' ' + '\n' + '',
30+
'newline'
31+
)
32+
).to.be.deep.equal(['a', 'b', 'c']);
33+
});
34+
});
35+
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /