public async copyResults()

in src/controllers/queryRunner.ts [394:502]


	public async copyResults(selection: ISlickRange[], batchId: number, resultId: number, includeHeaders?: boolean): Promise<void> {
		let copyString = '';

		// add the column headers
		if (this.shouldIncludeHeaders(includeHeaders)) {
			let firstCol: number;
			let lastCol: number;
			for (let range of selection) {
				if (firstCol === undefined || (range.fromCell < firstCol)) {
					firstCol = range.fromCell;
				}
				if (lastCol === undefined || (range.toCell > lastCol)) {
					lastCol = range.toCell;
				}
			}
			let columnRange: ISlickRange = {
				fromCell: firstCol,
				toCell: lastCol,
				fromRow: undefined,
				toRow: undefined
			};
			let columnHeaders = this.getColumnHeaders(batchId, resultId, columnRange);
			copyString += columnHeaders.join('\t');
			copyString += os.EOL;
		}

		// sort the selections by row to maintain copy order
		selection.sort((a, b) => a.fromRow - b.fromRow);

		// create a mapping of rows to selections
		let rowIdToSelectionMap = new Map<number, ISlickRange[]>();
		let rowIdToRowMap = new Map<number, DbCellValue[]>();

		// create a mapping of the ranges to get promises
		let tasks = selection.map((range) => {
			return async () => {
				const result = await this.getRows(range.fromRow, range.toRow - range.fromRow + 1, batchId, resultId);
				for (let row of result.resultSubset.rows) {
					let rowNumber = row[0].rowId + range.fromRow;
					if (rowIdToSelectionMap.has(rowNumber)) {
						let rowSelection = rowIdToSelectionMap.get(rowNumber);
						rowSelection.push(range);
					} else {
						rowIdToSelectionMap.set(rowNumber, [range]);
					}
					rowIdToRowMap.set(rowNumber, row);
				}
			};
		});

		// get all the rows
		let p = tasks[0]();
		for (let i = 1; i < tasks.length; i++) {
			p = p.then(tasks[i]);
		}
		await p;

		// Go through all rows and get selections for them
		let allRowIds = rowIdToRowMap.keys();
		const endColumns = this.getSelectionEndColumns(rowIdToRowMap, rowIdToSelectionMap);
		const firstColumn = endColumns[0];
		const lastColumn = endColumns[1];
		for (let rowId of allRowIds) {
			let row = rowIdToRowMap.get(rowId);
			const rowSelections = rowIdToSelectionMap.get(rowId);

			// sort selections by column to go from left to right
			rowSelections.sort((a, b) => {
				return ((a.fromCell < b.fromCell) ? -1 : (a.fromCell > b.fromCell) ? 1 : 0);
			});

			for (let i = 0; i < rowSelections.length; i++) {
				let rowSelection = rowSelections[i];

				// Add tabs starting from the first column of the selection
				for (let j = firstColumn; j < rowSelection.fromCell; j++) {
					copyString += '\t';
				}
				let cellObjects = row.slice(rowSelection.fromCell, (rowSelection.toCell + 1));

				// Remove newlines if requested
				let cells = this.shouldRemoveNewLines()
					? cellObjects.map(x => this.removeNewLines(x.displayValue))
					: cellObjects.map(x => x.displayValue);
				copyString += cells.join('\t');

				// Add tabs until the end column of the selection
				for (let k = rowSelection.toCell; k < lastColumn; k++) {
					copyString += '\t';
				}
			}
			copyString += os.EOL;
		}

		// Remove the last extra new line
		if (copyString.length > 1) {
			copyString = copyString.substring(0, copyString.length - os.EOL.length);
		}

		let oldLang: string;
		if (process.platform === 'darwin') {
			oldLang = process.env['LANG'];
			process.env['LANG'] = 'en_US.UTF-8';
		}
		await this._vscodeWrapper.clipboardWriteText(copyString);
		if (process.platform === 'darwin') {
			process.env['LANG'] = oldLang;
		}
	}