Page 1 of 2

Выполнение программ через External Tools

Posted: 05.09.2019 09:11
by boykobb
Недавно в англоязычной ветке форума пытался выяснить проблему или скорее проблемы, относящиеся к External Tools. Ответа не было – возможно, я не достаточно понятно спросил. Поэтому попробую здесь.

Итак, одна из проблем состоит в следующем. Вики утверждает здесь, что при помощи описываемого инструмента можно запускать программу (там говорится о C/C++, но это, конечно, несущественно).
Однако легко убедиться, что любая программа, требующая ввод со стандартного вводного канала, скажем

Code: Select all

#include <iostream>
int main() {int a,b; std::cin >> a >> b; std::cout << a+b << '\n';}
будет работать неправильно, так как никакого ввода вообще не выполняется.
В о.с. Windows еще можно обойти проблему, перенаправляя стандартный ввод на какой-нибудь файл и записывая это в Parameters инструмента – не то же самое, что иметь возможность вводить с клавиатуры, но хоть какое-то решение. А в Линуксе даже это не пройдет.
В связи с этим хотел спросить: возможно ли это положение исправить? Ведь возможность запускать только программы без ввода трудно считать полезной.

Posted: 05.09.2019 13:11
by kvichans
Для общения с пользователем поток stdin пригоден, но это не более.
Его полезность вызывает большие сомнения.
1. Чтобы получить от пользователя содержательный ответ, нужно задать ему содержательный вопрос.
Но голая текстовая среда (командная строка или ее замена) ограничены в возможностях.
2. Часто сложные ответы на все возможные вопросы можно сформировать до вызова.
Это путь конфигов. ExtTools в таком случае хорошо работает (я его для этого и делал):
- пользователь редактирует конфиг файл,
- при запуске тула этот файл подхватывается.
3. В сложных ситуациях, приходится переходить на GUI, чтобы пользователь осознал все данные для принятия решения.

И конечно, типичное применение ExtTools - это запуск компилятора/линкера/линтера/..., которым нечего от пользователя не нужно.

Posted: 05.09.2019 15:00
by boykobb
> Для общения с пользователем поток stdin пригоден, но это не более.
> Его полезность вызывает большие сомнения.

Иногда всё, что нужно – это как раз простое общение с пользователем.
Только бы оно было в расположении, а в данном случае не так.
Причём простое общение именно через stdin/stdout, полезность которых у меня не вызывает абсолютно никаких сомнений (и это даже не упоминая о перенаправливании, фильтрах, конвейерах и пр. фундаментальных в о.с. вещах).

Функционирование неисчислимого количества программ немыслимо без использования stdin/stdout.
В изучении программирования на любом языке и в любом возрасте, в школах, вузах и самостоятельно, единственным средством общения программы с миром как правило является та же пара stdin/stdout.
Это особо жёстко соблюдается на экзаменах, олимпиадах и т.д. для школьников и студентов во всём мире.

А намеревался предложить редактор CudaText как одна из выбираемых возможностей для программирования и соревнований в школьной и вузовской среде.
Но для этого нужно иметь в расположении удобный способ выполнять программу прямо «в редакторе».
В худшем случае – выполнять программу, запуская её в терминальную/консольную среду, стартируемую из редактора.
Это должно работать как в Windows, так и в Linux.
К сожалению, пока CudaText + External Tools не может этого делать.

Posted: 06.09.2019 15:09
by Alexey
я взял пример консольной программы в Вин10. это Python 3.5 python.exe. сделал такой тул в плагине
Ext Tools. и тул пускает черное окно питона с консольным вводом. я могу вводить там.
делать ввод прямо в самой Куде, в ее панели, не получается.

параметры тула.
File name: c:\Python35-32\python.exe
[x] Shell command (можно отметить или нет)
parameters: пусто
initial folder: {FileDir}
capture output: ignore (важно)

2й вариант тула.
file name: cmd.exe
[x] Shell command
parameters: /k c:\\Python35-32\\python.exe
тут я ввел двойные слеши, иначе плагин давал ошибку при запуске. видимо баг плагина.
initial folder: {FileDir}
capture output: ignore

Posted: 06.09.2019 22:00
by boykobb
Алексей,

Ваш второй вариант я упоминал раньше. Им, только в общем виде (для
любой запускаемой программы) пользуюсь в качестве резервного варианта
(см. левую часть приложенной картинки). Однако это работает только для
Windows, а аналог для Linux (правая часть картинки), к сожалению,
никак не работает. Как писал раньше, запускать bash или скрипт
никак не получается. А поскольку и запускать программу в Output panel
нельзя, то в результате в Linux пока нет способа запускать программу из
редактора.

Бойко

Posted: 07.09.2019 06:18
by Alexey
вот тут совет как пускать xterm без закрытия его черного окна.
https://stackoverflow.com/questions/108 ... erminating

у меня такой тул пускает в Терме команду "uname -a" и окно видно.

file name: xterm
[ ] Shell cmd
parameters: -hold -e uname -a
capture: ignore

попробуйте с Сишной программой.

Posted: 07.09.2019 08:27
by Alexey
получаются такие тулы для Си программ.
Винда: https://wiki.freepascal.org/CudaText#To ... n_terminal
Линукс: https://wiki.freepascal.org/CudaText#To ... n_terminal

Posted: 07.09.2019 16:52
by boykobb
Алексей,

В Windows задавать

Code: Select all

cmd /K программа && pause
(т.е. и /K, и pause) не имеет смысла. /K это и делает, что предотвращает закрытие консоли после выполнения программы, но в таком случае pause – лишнее, а консоль рано или поздно всё равно придётся закрывать самому.
Лучше

Code: Select all

cmd /C программа && pause
так как здесь консоль закроется автоматически, но только после нажатия клавиши пользователем.

Что до Линукса, у меня немного иначе. По подразумеванию в системе не имеется xterm, а gnome-terminal. Его я запускаю с
Parameters:

Code: Select all

-- bash -c "./{FileNameNoExt}; read -s -n1 -r -p 'Press any key to continue ... '; echo"
В данном случае выполнение программы в терминале выглядит внешне в точности как выполнение её в консоли Windows.

Также удобно иметь инструмент, который запускает лишь терминал и bash в директории редактируемого файла. Для этого я запускаю gnome-terminal без аргументов, что равнозначно запуску с аргументом -- bash.

Удовлетворяет ли решение в таком стиле? Да, если цель – решить задачу про себя. Но данное решение не универсально. У кого-то в Линуксе терминал – xterm, у другого – gnome-terminal, у третьего – konsole и т.д. Получается, что для решения задачи не хватает абстрактного уровня. Абстракция ломается даже из-за явного обращения к bash (вдруг у кого-то не bash, а tcsh или zsh, например). Лучше было бы вызывать оболочку через $SHELL или через слово, которое сам плагин предоставляет, и никак не ссылаться ни на имена терминальных программ, ни на специфику той или иной конкретной оболочки. Это и будет настоящим решением.

Бойко

Posted: 08.09.2019 06:32
by Alexey
для универсального шелла- не знаю как это сделать, $SHELL работает, но аргументы-то надо разные шеллам разным.

две ссылки выше- в вики- поправил под ваше замечание.

Posted: 09.09.2019 07:52
by boykobb
Вызывать «универсальную оболочку» скорее всего возможно, если под ней понимать sh, как определено согласно POSIX. При этом приведенное выше решение придется немного изменить, так как read в POSIX работает не так, как в bash. Но зато получим решение, которое работает в любой POSIX о.с., а не только в Linux.

Конкретнее, пусть переменная оболочки term имеет значением имя терминального эмулятора (как этого добиться, скажу чуть позже). Пусть также переменная pgm хранит имя программы, которую нужно выполнить в терминале. Тогда это выполнение можно сделать вызовом:

Code: Select all

$term -e sh -c "./$pgm; echo 'Press <Enter> to continue ... '; read -r x"
Здесь read уже не функция, а команда, и читает всю строку до конца, так что для закрытия терминала нужно нажать именно Enter, а не, как прежде, «any key». (И подсказка выдается не самим read, а отдельной командой echo.)

Более досадна проблема с тем, какой терминальный эмулятор вызывать. Ни в POSIX, ни в Linux понятие стандартного или подразумевающегося терминального эмулятора не определяется. Оно есть в системах, производных от Debian (имя x-terminal-emulator), что неплохо, но недостаточно универсально как решение для всех линуксов. Более универсальный, фактически очень близкий к полной универсальности метод – выполнить, опять-таки в sh:

Code: Select all

for term in $TERMINAL x-terminal-emulator gnome-terminal xterm mate-terminal rxvt urxvt xfce4-terminal terminator termite terminology qterminal konsole guake; do
  if command -v $term > /dev/null 2>&1; then break; fi
done
(Данный скрипт выберет первый имеющийся терминал из списка и присвоит его term. Этот метод я позаимствовал отсюда.)
Итак, для определения значения term пользуемся этим скриптом, а потом выполняем то, что дал выше (дав {FileNameNoExt} в качестве значения pgm).

Отмечу, что пользуемся sh дважды, на разных уровнях. Верхний уровень – выполнение двух указанных фрагментов, а нижний – тот sh, который вызывается терминальным эмулятором, чтобы в свою очередь вызвал пользовательскую программу. Нижнему sh терминал нужен, а верхнему – нет.

Остается отметить, что гораздо удобнее, если данное решение встроено в редактор (или в plug-in к нему), чем заставлять пользователя самому изобретать или даже копировать его. В конце концов, пользователю должно быть достаточно сказать: «выполнить эту программу» (понятно какую – ту, что в редакторе, и также понятно, что текущей директорией должна быть та, где сама программа лежит), возможно, задав лишь какие-нибудь аргументы вызова или перенаправливания ввода/вывода, а не заставлять его проходить через вышеописанные детали. Пользователю выполнять программы нужно, а подробности о том, как заставить Linux делать это, не его дело. То же относится и к Windows, только там этих подробностей не так много.