/* ** Do a shell command, with the options allowed to users (input source, ** output destination, save first and load after) in the shell commands ** menu. */ void DoShellMenuCmd(WindowInfo *window, const char *command, int input, int output, int outputReplacesInput, int saveFirst, int loadAfter, int fromMacro) { int flags = 0; char *text; char *subsCommand, fullName[MAXPATHLEN]; int left, right, textLen; int pos, line, column; char lineNumber[11]; WindowInfo *inWindow = window; Widget outWidget; /* Can't do two shell commands at once in the same window */ if (window->shellCmdData != NULL) { XBell(TheDisplay, 0); return; } /* Substitute the current file name for % and the current line number for # in the shell command */ strcpy(fullName, window->path); strcat(fullName, window->filename); pos = TextGetCursorPos(window->lastFocus); TextPosToLineAndCol(window->lastFocus, pos, &line, &column); sprintf(lineNumber, "%d", line); subsCommand = shellCommandSubstitutes(command, fullName, lineNumber); if (subsCommand == NULL) { DialogF(DF_ERR, window->shell, 1, "Shell Command", "Shell command is too long due to\n" "filename substitutions with '%%' or\n" "line number substitutions with '#'", "OK"); return; } /* Get the command input as a text string. If there is input, errors shouldn't be mixed in with output, so set flags to ERROR_DIALOGS */ if (input == FROM_SELECTION) { text = BufGetSelectionText(window->buffer); if (*text == '\0') { XtFree(text); free(subsCommand); XBell(TheDisplay, 0); return; } flags |= ACCUMULATE | ERROR_DIALOGS; } else if (input == FROM_WINDOW) { text = BufGetAll(window->buffer); flags |= ACCUMULATE | ERROR_DIALOGS; } else if (input == FROM_EITHER) { text = BufGetSelectionText(window->buffer); if (*text == '\0') { XtFree(text); text = BufGetAll(window->buffer); } flags |= ACCUMULATE | ERROR_DIALOGS; } else /* FROM_NONE */ text = NULL; /* If the buffer was substituting another character for ascii-nuls, put the nuls back in before exporting the text */ if (text != NULL) { textLen = strlen(text); BufUnsubstituteNullChars(text, window->buffer); } else textLen = 0; /* Assign the output destination. If output is to a new window, create it, and run the command from it instead of the current one, to free the current one from waiting for lengthy execution */ if (output == TO_DIALOG) { outWidget = NULL; flags |= OUTPUT_TO_DIALOG; left = right = 0; } else if (output == TO_NEW_WINDOW) { EditNewFile(GetPrefOpenInTab()?inWindow:NULL, NULL, False, NULL, window->path); outWidget = WindowList->textArea; inWindow = WindowList; left = right = 0; CheckCloseDim(); } else { /* TO_SAME_WINDOW */ outWidget = window->lastFocus; if (outputReplacesInput && input != FROM_NONE) { if (input == FROM_WINDOW) { left = 0; right = window->buffer->length; } else if (input == FROM_SELECTION) { GetSimpleSelection(window->buffer, &left, &right); flags |= ACCUMULATE | REPLACE_SELECTION; } else if (input == FROM_EITHER) { if (GetSimpleSelection(window->buffer, &left, &right)) flags |= ACCUMULATE | REPLACE_SELECTION; else { left = 0; right = window->buffer->length; } } } else { if (GetSimpleSelection(window->buffer, &left, &right)) flags |= ACCUMULATE | REPLACE_SELECTION; else left = right = TextGetCursorPos(window->lastFocus); } } /* If the command requires the file be saved first, save it */ if (saveFirst) { if (!SaveWindow(window)) { if (input != FROM_NONE) XtFree(text); free(subsCommand); return; } } /* If the command requires the file to be reloaded after execution, set a flag for issueCommand to deal with it when execution is complete */ if (loadAfter) flags |= RELOAD_FILE_AFTER; /* issue the command */ issueCommand(inWindow, subsCommand, text, textLen, flags, outWidget, left, right, fromMacro); free(subsCommand); }
/* ** Start the process of dragging the current primary-selected text across ** the window (move by dragging, as opposed to dragging to create the ** selection) */ void BeginBlockDrag(TextWidget tw) { textDisp *textD = tw->text.textD; textBuffer *buf = textD->buffer; int fontHeight = textD->fontStruct->ascent + textD->fontStruct->descent; int fontWidth = textD->fontStruct->max_bounds.width; selection *sel = &buf->primary; int nLines, mousePos, lineStart; int x, y, lineEnd; char *text; /* Save a copy of the whole text buffer as a backup, and for deriving changes */ tw->text.dragOrigBuf = BufCreate(); BufSetTabDistance(tw->text.dragOrigBuf, buf->tabDist); tw->text.dragOrigBuf->useTabs = buf->useTabs; text = BufGetAll(buf); BufSetAll(tw->text.dragOrigBuf, text); XtFree(text); if (sel->rectangular) BufRectSelect(tw->text.dragOrigBuf, sel->start, sel->end, sel->rectStart, sel->rectEnd); else BufSelect(tw->text.dragOrigBuf, sel->start, sel->end); /* Record the mouse pointer offsets from the top left corner of the selection (the position where text will actually be inserted In dragging non-rectangular selections) */ if (sel->rectangular) { tw->text.dragXOffset = tw->text.btnDownX + textD->horizOffset - textD->left - sel->rectStart * fontWidth; } else { if (!TextDPositionToXY(textD, sel->start, &x, &y)) x = BufCountDispChars(buf, TextDStartOfLine(textD, sel->start), sel->start) * fontWidth + textD->left - textD->horizOffset; tw->text.dragXOffset = tw->text.btnDownX - x; } mousePos = TextDXYToPosition(textD, tw->text.btnDownX, tw->text.btnDownY); nLines = BufCountLines(buf, sel->start, mousePos); tw->text.dragYOffset = nLines * fontHeight + (((tw->text.btnDownY - tw->text.marginHeight) % fontHeight) - fontHeight/2); tw->text.dragNLines = BufCountLines(buf, sel->start, sel->end); /* Record the current drag insert position and the information for undoing the fictional insert of the selection in its new position */ tw->text.dragInsertPos = sel->start; tw->text.dragInserted = sel->end - sel->start; if (sel->rectangular) { textBuffer *testBuf = BufCreate(); char *testText = BufGetRange(buf, sel->start, sel->end); BufSetTabDistance(testBuf, buf->tabDist); testBuf->useTabs = buf->useTabs; BufSetAll(testBuf, testText); XtFree(testText); BufRemoveRect(testBuf, 0, sel->end - sel->start, sel->rectStart, sel->rectEnd); tw->text.dragDeleted = testBuf->length; BufFree(testBuf); tw->text.dragRectStart = sel->rectStart; } else { tw->text.dragDeleted = 0; tw->text.dragRectStart = 0; } tw->text.dragType = DRAG_MOVE; tw->text.dragSourceDeletePos = sel->start; tw->text.dragSourceInserted = tw->text.dragDeleted; tw->text.dragSourceDeleted = tw->text.dragInserted; /* For non-rectangular selections, fill in the rectangular information in the selection for overlay mode drags which are done rectangularly */ if (!sel->rectangular) { lineStart = BufStartOfLine(buf, sel->start); if (tw->text.dragNLines == 0) { tw->text.dragOrigBuf->primary.rectStart = BufCountDispChars(buf, lineStart, sel->start); tw->text.dragOrigBuf->primary.rectEnd = BufCountDispChars(buf, lineStart, sel->end); } else { lineEnd = BufGetCharacter(buf, sel->end - 1) == '\n' ? sel->end - 1 : sel->end; findTextMargins(buf, lineStart, lineEnd, &tw->text.dragOrigBuf->primary.rectStart, &tw->text.dragOrigBuf->primary.rectEnd); } } /* Set the drag state to announce an ongoing block-drag */ tw->text.dragState = PRIMARY_BLOCK_DRAG; /* Call the callback announcing the start of a block drag */ XtCallCallbacks((Widget)tw, textNdragStartCallback, (XtPointer)NULL); }