Add a config for copying with trailing line break (#23481)

This commit is contained in:
Hai Cao
2023-06-28 14:34:52 -07:00
committed by GitHub
parent 0f7178f4a0
commit 4869ebab51
9 changed files with 31 additions and 12 deletions

View File

@@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IDataResource, rowHasColumnNameKeys } from 'sql/workbench/services/notebook/browser/sql/sqlSessionManager';
import { getEolString, shouldIncludeHeaders, shouldRemoveNewLines } from 'sql/workbench/services/query/common/queryRunner';
import { getEolString, shouldSkipNewLineAfterTrailingLineBreak, shouldIncludeHeaders, shouldRemoveNewLines } from 'sql/workbench/services/query/common/queryRunner';
import { ResultSetSummary, ResultSetSubset, ICellValue } from 'sql/workbench/services/query/common/query';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
@@ -441,6 +441,9 @@ export class DataResourceDataProvider implements IGridDataProvider {
shouldRemoveNewLines(): boolean {
return shouldRemoveNewLines(this._configurationService);
}
shouldSkipNewLineAfterTrailingLineBreak(): boolean {
return shouldSkipNewLineAfterTrailingLineBreak(this._configurationService);
}
getColumnHeaders(range: Slick.Range): string[] {
let headers: string[] = this._resultSet.columnInfo.slice(range.fromCell, range.toCell + 1).map((info, i) => {

View File

@@ -303,6 +303,11 @@ const queryEditorConfiguration: IConfigurationNode = {
'description': localize('queryEditor.results.copyRemoveNewLine', "Configuration options for copying multi-line results from the Results View"),
'default': true
},
'queryEditor.results.skipNewLineAfterTrailingLineBreak': {
'type': 'boolean',
'description': localize('queryEditor.results.skipNewLineAfterTrailingLineBreak', "Whether to skip adding a line break between rows when copying results if the previous row already has a trailing line break. The default value is false."),
'default': false
},
'queryEditor.results.preferProvidersCopyHandler': {
'type': 'boolean',
'description': localize('queryEditor.results.preferProvidersCopyHandler', "Whether the copy result request should be handled by the query provider when it is supported. The default value is true, set this to false to force all copy handling to be done by Azure Data Studio."),

View File

@@ -46,6 +46,8 @@ export interface IGridDataProvider {
shouldRemoveNewLines(): boolean;
shouldSkipNewLineAfterTrailingLineBreak(): boolean;
getColumnHeaders(range: Slick.Range): string[] | undefined;
readonly canSerialize: boolean;
@@ -101,6 +103,7 @@ export async function copySelectionToClipboard(clipboardService: IClipboardServi
const eol = provider.getEolString();
const valueSeparator = '\t';
const shouldRemoveNewLines = provider.shouldRemoveNewLines();
const shouldSkipNewLineAfterTrailingLineBreak = provider.shouldSkipNewLineAfterTrailingLineBreak();
// Merge the selections to get the unique columns and unique rows.
const gridRanges = GridRange.fromSlickRanges(selections);
@@ -154,7 +157,9 @@ export async function copySelectionToClipboard(clipboardService: IClipboardServi
});
}
if (!cancellationTokenSource.token.isCancellationRequested) {
resultString += rowValues.join(eol);
resultString += rowValues.reduce(
(prevVal, currVal, idx) => prevVal + (idx > 0 && (!prevVal?.endsWith(eol) || !shouldSkipNewLineAfterTrailingLineBreak) ? eol : '') + currVal,
);
await clipboardService.writeText(resultString);
}
}, cancellationTokenSource);

View File

@@ -465,15 +465,13 @@ export default class QueryRunner extends Disposable {
* @param selections The selection range to copy
* @param batchId The batch id of the result to copy from
* @param resultId The result id of the result to copy from
* @param removeNewLines Whether to remove line breaks from values.
* @param includeHeaders [Optional]: Should column headers be included in the copy selection
*/
async copyResults(selections: Slick.Range[], batchId: number, resultId: number, removeNewLines: boolean, includeHeaders?: boolean): Promise<void> {
async copyResults(selections: Slick.Range[], batchId: number, resultId: number, includeHeaders?: boolean): Promise<void> {
await this.queryManagementService.copyResults({
ownerUri: this.uri,
batchIndex: batchId,
resultSetIndex: resultId,
removeNewLines: removeNewLines,
includeHeaders: includeHeaders,
selections: selections.map(selection => {
return {
@@ -592,7 +590,7 @@ export class QueryGridDataProvider implements IGridDataProvider {
private async handleCopyRequestByProvider(selections: Slick.Range[], includeHeaders?: boolean): Promise<void> {
executeCopyWithNotification(this._notificationService, selections, async () => {
await this.queryRunner.copyResults(selections, this.batchId, this.resultSetId, this.shouldRemoveNewLines(), this.shouldIncludeHeaders(includeHeaders));
await this.queryRunner.copyResults(selections, this.batchId, this.resultSetId, this.shouldIncludeHeaders(includeHeaders));
});
}
@@ -614,6 +612,9 @@ export class QueryGridDataProvider implements IGridDataProvider {
shouldRemoveNewLines(): boolean {
return shouldRemoveNewLines(this._configurationService);
}
shouldSkipNewLineAfterTrailingLineBreak(): boolean {
return shouldSkipNewLineAfterTrailingLineBreak(this._configurationService);
}
getColumnHeaders(range: Slick.Range): string[] | undefined {
return this.queryRunner.getColumnHeaders(this.batchId, this.resultSetId, range);
}
@@ -648,6 +649,12 @@ export function shouldRemoveNewLines(configurationService: IConfigurationService
return !!removeNewLines;
}
export function shouldSkipNewLineAfterTrailingLineBreak(configurationService: IConfigurationService): boolean {
// get config skipNewLineAfterTrailingLineBreak option from vscode config
let skipNewLineAfterTrailingLineBreak = configurationService.getValue<IQueryEditorConfiguration>('queryEditor').results.skipNewLineAfterTrailingLineBreak;
return !!skipNewLineAfterTrailingLineBreak;
}
function isRangeOrUndefined(input: string | IRange | undefined): input is IRange | undefined {
return Range.isIRange(input) || types.isUndefinedOrNull(input);
}