mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Copy clipboard command in ADS (html/plain text supported) (#13527)
* draft commit * few changes * Changes to copy query with results in plain and html formatting * undo changes * undo unintended change * remove comments * Addressed comments * Some clean up Co-authored-by: Monica Gupta <mogupt@microsoft.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||||
import { IClipboardService as vsIClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { ClipboardData, IClipboardService as vsIClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
@@ -25,6 +25,10 @@ export class BrowserClipboardService implements IClipboardService {
|
|||||||
this._notificationService.info(localize('imageCopyingNotSupported', "Copying images is not supported"));
|
this._notificationService.info(localize('imageCopyingNotSupported', "Copying images is not supported"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write(data: ClipboardData): Promise<void> {
|
||||||
|
return this._vsClipboardService.write(data);
|
||||||
|
}
|
||||||
|
|
||||||
writeText(text: string): Promise<void> {
|
writeText(text: string): Promise<void> {
|
||||||
return this._vsClipboardService.writeText(text);
|
return this._vsClipboardService.writeText(text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { Action } from 'vs/base/common/actions';
|
|||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
|
import { escape } from 'sql/base/common/strings';
|
||||||
|
|
||||||
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
@@ -21,6 +22,7 @@ import { EditDataEditor } from 'sql/workbench/contrib/editData/browser/editDataE
|
|||||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { QueryEditorInput } from 'sql/workbench/common/editor/query/queryEditorInput';
|
import { QueryEditorInput } from 'sql/workbench/common/editor/query/queryEditorInput';
|
||||||
|
import { ClipboardData, IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
|
|
||||||
const singleQuote = '\'';
|
const singleQuote = '\'';
|
||||||
|
|
||||||
@@ -131,6 +133,74 @@ export class RunCurrentQueryKeyboardAction extends Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CopyQueryWithResultsKeyboardAction extends Action {
|
||||||
|
public static ID = 'copyQueryWithResultsKeyboardAction';
|
||||||
|
public static LABEL = nls.localize('copyQueryWithResultsKeyboardAction', "Copy Query With Results");
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
id: string,
|
||||||
|
label: string,
|
||||||
|
@IEditorService private _editorService: IEditorService,
|
||||||
|
@IClipboardService private _clipboardService: IClipboardService,
|
||||||
|
@IQueryModelService protected readonly queryModelService: IQueryModelService,
|
||||||
|
) {
|
||||||
|
super(id, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getFormattedResults(editor): Promise<ClipboardData> {
|
||||||
|
let queryRunner = this.queryModelService.getQueryRunner(editor.input.uri);
|
||||||
|
let allResults = '';
|
||||||
|
let allHtmlResults = '';
|
||||||
|
|
||||||
|
if (queryRunner && queryRunner.batchSets.length > 0) {
|
||||||
|
for (let i = 0; i < queryRunner.batchSets[0].resultSetSummaries.length; i++) {
|
||||||
|
let resultSummary = queryRunner.batchSets[0].resultSetSummaries[i];
|
||||||
|
let result = await queryRunner.getQueryRows(0, resultSummary.rowCount, resultSummary.batchId, resultSummary.id);
|
||||||
|
let tableHeaders = resultSummary.columnInfo.map((col, i) => (col.columnName));
|
||||||
|
let htmlTableHeaders = resultSummary.columnInfo.map((col, i) => (`<th style="border:solid black 1.0pt; whiteSpace:nowrap">${escape(col.columnName)}</th>`));
|
||||||
|
let copyString = '\n';
|
||||||
|
let htmlCopyString = '<tr>';
|
||||||
|
|
||||||
|
for (let rowEntry of result.rows) {
|
||||||
|
for (let colIdx = 0; colIdx < rowEntry.length; colIdx++) {
|
||||||
|
let value = rowEntry[colIdx].displayValue;
|
||||||
|
if (value) {
|
||||||
|
copyString = `${copyString}${value}\t`;
|
||||||
|
htmlCopyString = `${htmlCopyString}<td style="border:solid black 1.0pt;white-space:nowrap">${escape(value)}</td>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Removes the tab seperator from the end of a row
|
||||||
|
copyString = copyString.slice(0, -1 * '\t'.length) + '\n';
|
||||||
|
htmlCopyString = htmlCopyString + '</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
allResults = `${allResults}${tableHeaders.join('\t')}${copyString}\n`;
|
||||||
|
allHtmlResults = `${allHtmlResults}<div><br/><br/>
|
||||||
|
<table cellPadding="5" cellSpacing="1" style="border:1;border-color:Black;font-family:Segoe UI;font-size:12px;border-collapse:collapse">
|
||||||
|
<tr style="background-color:DarkGray">${htmlTableHeaders.join('')}</tr>${htmlCopyString}
|
||||||
|
</table></div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { text: allResults, html: allHtmlResults };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async run(): Promise<void> {
|
||||||
|
const editor = this._editorService.activeEditorPane;
|
||||||
|
if (editor instanceof QueryEditor) {
|
||||||
|
let allResults = await this.getFormattedResults(editor);
|
||||||
|
let queryText = editor.getAllText();
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
text: `${queryText}\n\n${allResults.text}`,
|
||||||
|
html: `${escape(queryText).replace(/\r\n|\n|\r/gm, '<br />')}${allResults.html}`
|
||||||
|
};
|
||||||
|
|
||||||
|
await this._clipboardService.write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class RunCurrentQueryWithActualPlanKeyboardAction extends Action {
|
export class RunCurrentQueryWithActualPlanKeyboardAction extends Action {
|
||||||
public static ID = 'runCurrentQueryWithActualPlanKeyboardAction';
|
public static ID = 'runCurrentQueryWithActualPlanKeyboardAction';
|
||||||
public static LABEL = nls.localize('runCurrentQueryWithActualPlanKeyboardAction', "Run Current Query with Actual Plan");
|
public static LABEL = nls.localize('runCurrentQueryWithActualPlanKeyboardAction', "Run Current Query with Actual Plan");
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { QueryResultsInput } from 'sql/workbench/common/editor/query/queryResult
|
|||||||
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
|
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
|
||||||
import {
|
import {
|
||||||
RunQueryKeyboardAction, RunCurrentQueryKeyboardAction, CancelQueryKeyboardAction, RefreshIntellisenseKeyboardAction, ToggleQueryResultsKeyboardAction,
|
RunQueryKeyboardAction, RunCurrentQueryKeyboardAction, CancelQueryKeyboardAction, RefreshIntellisenseKeyboardAction, ToggleQueryResultsKeyboardAction,
|
||||||
RunQueryShortcutAction, RunCurrentQueryWithActualPlanKeyboardAction, FocusOnCurrentQueryKeyboardAction, ParseSyntaxAction
|
RunQueryShortcutAction, RunCurrentQueryWithActualPlanKeyboardAction, CopyQueryWithResultsKeyboardAction, FocusOnCurrentQueryKeyboardAction, ParseSyntaxAction
|
||||||
} from 'sql/workbench/contrib/query/browser/keyboardQueryActions';
|
} from 'sql/workbench/contrib/query/browser/keyboardQueryActions';
|
||||||
import * as gridActions from 'sql/workbench/contrib/editData/browser/gridActions';
|
import * as gridActions from 'sql/workbench/contrib/editData/browser/gridActions';
|
||||||
import * as gridCommands from 'sql/workbench/contrib/editData/browser/gridCommands';
|
import * as gridCommands from 'sql/workbench/contrib/editData/browser/gridCommands';
|
||||||
@@ -139,6 +139,16 @@ actionRegistry.registerWorkbenchAction(
|
|||||||
RunCurrentQueryWithActualPlanKeyboardAction.LABEL
|
RunCurrentQueryWithActualPlanKeyboardAction.LABEL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
actionRegistry.registerWorkbenchAction(
|
||||||
|
SyncActionDescriptor.create(
|
||||||
|
CopyQueryWithResultsKeyboardAction,
|
||||||
|
CopyQueryWithResultsKeyboardAction.ID,
|
||||||
|
CopyQueryWithResultsKeyboardAction.LABEL,
|
||||||
|
{ primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C }
|
||||||
|
),
|
||||||
|
CopyQueryWithResultsKeyboardAction.LABEL
|
||||||
|
);
|
||||||
|
|
||||||
actionRegistry.registerWorkbenchAction(
|
actionRegistry.registerWorkbenchAction(
|
||||||
SyncActionDescriptor.create(
|
SyncActionDescriptor.create(
|
||||||
CancelQueryKeyboardAction,
|
CancelQueryKeyboardAction,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { ClipboardData, IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; // {{SQL CARBON EDIT}}
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { $ } from 'vs/base/browser/dom';
|
import { $ } from 'vs/base/browser/dom';
|
||||||
|
|
||||||
@@ -13,6 +13,11 @@ export class BrowserClipboardService implements IClipboardService {
|
|||||||
|
|
||||||
private readonly mapTextToType = new Map<string, string>(); // unsupported in web (only in-memory)
|
private readonly mapTextToType = new Map<string, string>(); // unsupported in web (only in-memory)
|
||||||
|
|
||||||
|
// {{SQL CARBON EDIT}}
|
||||||
|
async write(data: ClipboardData, type?: string): Promise<void> {
|
||||||
|
throw new Error('Not Implemented');
|
||||||
|
}
|
||||||
|
|
||||||
async writeText(text: string, type?: string): Promise<void> {
|
async writeText(text: string, type?: string): Promise<void> {
|
||||||
|
|
||||||
// With type: only in-memory is supported
|
// With type: only in-memory is supported
|
||||||
|
|||||||
@@ -8,9 +8,21 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
|
|
||||||
export const IClipboardService = createDecorator<IClipboardService>('clipboardService');
|
export const IClipboardService = createDecorator<IClipboardService>('clipboardService');
|
||||||
|
|
||||||
|
// Added type https://www.electronjs.org/docs/api/clipboard#clipboardwritedata-type
|
||||||
|
export interface ClipboardData { // {{SQL CARBON EDIT}}
|
||||||
|
text?: string;
|
||||||
|
html?: string;
|
||||||
|
rtf?: string;
|
||||||
|
bookmark?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IClipboardService {
|
export interface IClipboardService {
|
||||||
|
|
||||||
readonly _serviceBrand: undefined;
|
readonly _serviceBrand: undefined;
|
||||||
|
/**
|
||||||
|
* Writes data to the system clipboard.
|
||||||
|
*/
|
||||||
|
write(data: ClipboardData, type?: string): Promise<void>; // {{SQL CARBON EDIT}}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes text to the system clipboard.
|
* Writes text to the system clipboard.
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export interface ICommonElectronService {
|
|||||||
writeClipboardText(text: string, type?: 'selection' | 'clipboard'): Promise<void>;
|
writeClipboardText(text: string, type?: 'selection' | 'clipboard'): Promise<void>;
|
||||||
readClipboardFindText(): Promise<string>;
|
readClipboardFindText(): Promise<string>;
|
||||||
writeClipboardFindText(text: string): Promise<void>;
|
writeClipboardFindText(text: string): Promise<void>;
|
||||||
|
writeClipboardData(data: any, type?: 'selection' | 'clipboard'): Promise<void>; // {{SQL CARBON EDIT}}
|
||||||
writeClipboardBuffer(format: string, buffer: Uint8Array, type?: 'selection' | 'clipboard'): Promise<void>;
|
writeClipboardBuffer(format: string, buffer: Uint8Array, type?: 'selection' | 'clipboard'): Promise<void>;
|
||||||
readClipboardBuffer(format: string): Promise<Uint8Array>;
|
readClipboardBuffer(format: string): Promise<Uint8Array>;
|
||||||
hasClipboard(format: string, type?: 'selection' | 'clipboard'): Promise<boolean>;
|
hasClipboard(format: string, type?: 'selection' | 'clipboard'): Promise<boolean>;
|
||||||
|
|||||||
@@ -369,6 +369,11 @@ export class ElectronMainService implements IElectronMainService {
|
|||||||
return clipboard.writeText(text, type);
|
return clipboard.writeText(text, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {{SQL CARBON EDIT}}
|
||||||
|
async writeClipboardData(windowId: number | undefined, data: any, type?: 'selection' | 'clipboard'): Promise<void> {
|
||||||
|
return clipboard.write(data, type);
|
||||||
|
}
|
||||||
|
|
||||||
async readClipboardFindText(windowId: number | undefined,): Promise<string> {
|
async readClipboardFindText(windowId: number | undefined,): Promise<string> {
|
||||||
return clipboard.readFindText();
|
return clipboard.readFindText();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { ClipboardData, IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; // {{SQL CARBON EDIT}}
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { isMacintosh } from 'vs/base/common/platform';
|
import { isMacintosh } from 'vs/base/common/platform';
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
@@ -20,6 +20,11 @@ export class NativeClipboardService implements IClipboardService {
|
|||||||
@IElectronService private readonly electronService: IElectronService
|
@IElectronService private readonly electronService: IElectronService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
// {{SQL CARBON EDIT}}
|
||||||
|
async write(data: ClipboardData, type?: 'selection' | 'clipboard'): Promise<void> {
|
||||||
|
return this.electronService.writeClipboardData(data, type);
|
||||||
|
}
|
||||||
|
|
||||||
async writeText(text: string, type?: 'selection' | 'clipboard'): Promise<void> {
|
async writeText(text: string, type?: 'selection' | 'clipboard'): Promise<void> {
|
||||||
return this.electronService.writeClipboardText(text, type);
|
return this.electronService.writeClipboardText(text, type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ export class TestElectronService implements IElectronService {
|
|||||||
async toggleDevTools(): Promise<void> { }
|
async toggleDevTools(): Promise<void> { }
|
||||||
async resolveProxy(url: string): Promise<string | undefined> { return undefined; }
|
async resolveProxy(url: string): Promise<string | undefined> { return undefined; }
|
||||||
async readClipboardText(type?: 'selection' | 'clipboard' | undefined): Promise<string> { return ''; }
|
async readClipboardText(type?: 'selection' | 'clipboard' | undefined): Promise<string> { return ''; }
|
||||||
|
async writeClipboardData(data: any, type?: 'selection' | 'clipboard' | undefined): Promise<void> { } // {{SQL CARBON EDIT}}
|
||||||
async writeClipboardText(text: string, type?: 'selection' | 'clipboard' | undefined): Promise<void> { }
|
async writeClipboardText(text: string, type?: 'selection' | 'clipboard' | undefined): Promise<void> { }
|
||||||
async readClipboardFindText(): Promise<string> { return ''; }
|
async readClipboardFindText(): Promise<string> { return ''; }
|
||||||
async writeClipboardFindText(text: string): Promise<void> { }
|
async writeClipboardFindText(text: string): Promise<void> { }
|
||||||
|
|||||||
Reference in New Issue
Block a user