Страницы

Поиск по вопросам

четверг, 28 ноября 2019 г.

Различия методов Find(), FirstOrDefault() при использовании с Entity Framework

#c_sharp #.net #entity_framework #linq #c_sharp_faq


Если нужно получить запись из базы данных по ее первичному ключу, можно воспользоваться
и тем и другим методом. Оба метода вернут объект сущности, если запись присутствует
в базе, в противном случае вернут null.

В чем их разница и когда какой метод использовать?
    


Ответы

Ответ 1



Для поиска и получения объекта сущности можно воспользоваться методами: Find(), First(), FirstOrDefault(), Single(), SingleOrDefault(). Рассмотрим каждый: Метод Find() принимает в качестве параметра первичный ключ записи. Его особенность состоит в том, что в отличие от остальных методов, он сначала обращается к памяти и ищет запись среди объектов контекста, отслеживаемых EntityFramework'ом, и только потом (если ничего не нашел) выполняет запрос к бд. Если в контексте найдется объект, который еще не сохранен в базе, метод Find() все равно вернет его (с состоянием Added). Если запись не будет найдена ни там ни там, вернет null. Генерируемый SQL запрос: SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p0 Стоит обратить внимание, что в выборку попадает не одна запись, а две SELECT TOP (2). Это используется внутренними механизмами EF для проверки уникальности записи. Если в результате окажется более одной записи с одним и тем же первичным ключем, EF сгенерирует исключение: System.InvalidOperationException: "Последовательность содержит более одного элемента" Метод FirstOrDefault() принимает в качестве параметра предикат, что дает возможность искать не только по первичному ключу, но и по любому составленному условию. Например, найдем запись, у которой Title == "test": var topic = context.Topics.FirstOrDefault(topic => topic.Title == "test"); FirstOrDefault() в отличии от Find() каждый раз выполняет запрос к базе, не зависимо от того есть ли данные в контексте. Если из базы придет запись, отличающаяся от той что лежит в контексте, EF вернет запись из контекста. Если записи не окажется в базе, вернет null, даже если она есть в контексте. Генерируемый SQL запрос: SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p__linq__0 Тут ищет только одну запись SELECT TOP (1). Если окажется что записей несколько, вернет первую. Метод First() аналогичен FirstOrDefault() с одним отличием - если запись не найдена, будет сгенерировано исключение: System.InvalidOperationException: "Последовательность не содержит элементов" Метод SingleOrDefault() аналогичен FirstOrDefault() и возвращает объект сущности, либо null. Однако запрос генерирует подобный методу Find(): SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p__linq__0 И при обнаружении более одной записи выкидывает исключение: System.InvalidOperationException: "Последовательность содержит более одного элемента" Метод Single() аналогичен SingleOrDefault() и отличается тем, что если запись не найдена, будет сгенерировано исключение: System.InvalidOperationException: "Последовательность не содержит элементов" Подведем итоги: Когда использовать Find()? Когда искать нужно по первичному ключу и выбрать нужно все данные сущности. Find() не выполняет запрос, если запись уже загружена в контекст и, как следствие, будет превосходить в производительности все остальные методы. Однако если нужно выбрать какие-то определенные поля (например только Id и Title), придется воспользоваться остальными методами. То же касается и подгрузки зависимых данных (например через Include()) - Find() это сделать не даст. Когда использовать остальные методы? Если нужна выборка определенных полей сущности или нужно также загрузить зависимые данные. Какие именно методы использовать зависит от индивидуальных требований: если вам нужно проверить существование записи (без генерации исключений), подойдут методы *OrDefault(): var topic = context.Topics .Select(topic => new { topic.Id, topic.Title }) .FirstOrDefault(topic => topic.Id == 44); if (topic == null) { // ... } Если предполагается, что контекст может содержать локальные копии данных, можно получить их оттуда, не выполняя запроса к базе. Для этого нужно обратиться к свойству Local объекта DbSet: Var topic = context.Topics.Local.FirstOrDefault(topic => topic.Id == topicId) ?? context.Topics.FirstOrDefault(topic => topic.Id == topicId); Используемые источники: MSDN: Entity Framework Querying and Finding Entities Primer on Selecting Data Using Entity Framework StackOverflow: Are Find and Where().FirstOrDefault() equivalent? StackOverflow: Using .Find() & .Include() on the same query

Как работает GROUP BY в MySQL?

#mysql #sql


Привет.

Вопрос по sql по клаузуле GROUP BY. 


Рассмотрим группировку по ОДНОМУ столбцу. Пример:

SELECT DEPARTMENT_ID, SUM(SALARY) 
FROM Employees
GROUP BY DEPARTMENT_ID;




То есть, в столбце DEPARTMENT_ID ищется уникальное (похоже на DISTINCT) значение
отдела, например, 30, затем ищутся все строки, где упоминается отдел 30 в данной таблице,
из этих строк берутся значения из столбца SALARY и суммируются (SUM). Потом ищется
другой покупатель и все повторяется. В итоге я получаю сколько получил вообще денег
каждый отдел.

Не понимаю момент: у меня есть 6 строк, в которых есть столбец DEPARTMENT_ID со значением
30. Какая из строк пойдет в таблицу-SELECT и почему? То есть, в таблице Employees было
шесть строк с DEPARTMENT_ID 30, а в таблице-SELECT такая строка только одна. Как вообще
эта группировка работает?
Рассмотрим группировку по двум столбцам. Ее я вообще не понимаю. Даже картинки нормальной
не нашел, из которой было бы понятно. Просмотрел кучу статей и книг по этому вопросу,
но не понял ничего.

    


Ответы

Ответ 1



Добавлю с примером запросов и вывода GROUP BY по двух полях. Смотреть можна по таблице в которую например сохраняеться какой пользователь(user_id) вносил деньги, на какой счет(account) и сколько(balance). Например нужно узнать сколько каждый пользователь внес на каждый со своих счетов. SELECT MIN(user_id), MIN(account), SUM(balance) FROM `t1` GROUP BY user_id, account; Работает GROUP BY по двух полях так же как и по одному, сначала сортирует, а потом смотрит если оба значения в строке такие же как и в предыдущей строке тогда групирует эти строки. Если хотя бы одно значение не такое как в предыдущей строке тогда групировки не будет. Для 3 и больше полей GROUP BY работает так же. Результат:

Ответ 2



В выборку после group by не попадет ни одна из изначальных строк. На выходе агрегат - сумма данных в нужном разрезе. К колонкам, к которым вы явно не применили никаких групповых функций (таких как sum()), будет применена функция "первое попавшееся". Причем только в MySQL и только при выключенной опции ONLY_FULL_GROUP_BY. В остальных СУБД запрос, в котором хотя бы к одной колонке, не являющейся разрезом указанным в group by, "забыли" применить групповую функцию выдадут ошибку. Как работает group by можно прикинуть в экселе. Запишите данные на лист, отсортируйте по тем полям, которые должны быть в group by. Читая отсортированные данные подряд в любом случае когда значение в очередной строке в колонках, указанных в group by отличается от значений в предыдущей - вставьте новую строку, скопируйте значения колонок group by, а в остальные поместите формулы вроде СУММ() ячеек группы под которой подводится итог. Результат group by - это именно эти вставленные итоговые записи. СУБД работает примерно по такому же алгоритму - сначала сортирует, потом суммирует идущие подряд одинаковые записи. Добавлю про MySQL - он все таки слишком вольно к этому относится, старайтесь всегда явно применять групповые функции ко всем колонкам, что бы самому понимать что именно в них окажется, ибо 'первое попавшееся' ни чем не стандартизировано и может меняться от версии к версии и в зависимости от физического расположения записей на диске и плана выполнения запроса.

О логировании в java

#java #логирование


Приводится на хабре в статье библиотека Apache Commons Logging (не знаю смысл этой
библиотеки,  не юзал) и комментарий:


  За System.out.println для вывода логов начинающим программистам уже через неделю
обучения следует отрубать руки.


Так вот вопрос: а почему print настолько плох?

P.S. Сам я основы языка очень плохо знаю.
    


Ответы

Ответ 1



Логирование - это все-таки больше, чем вывод строк в консоль. Здесь имеют место следующие параметры: Цель: это может быть консоль (stdout), немного другая консоль (stderr), файл, удаленный сервер сбора логов Уровень логирования: для разных выводов может быть разный уровень вывода: например, в один файл мы скидываем всё, но храним только последние десять мегабайт, а в другой отправляем только сообщения уровня WARN и выше, но храним историю за последние шесть месяцев Per-package настройки: в случае, если "шалит" конкретный участок кода, можно включить логирование только для него Ротация логов: логи чаще всего надо хранить в файлах, которые нужно периодически подчищать, и при этом во время проведения работ продолжать писать логи Контекст выполнения: зачастую просто сообщения недостаточно (если транзакция провалилась, то какие входные параметры этому поспособтсвовали?), поэтому существуют штуки типа MDC, чтобы при обработке конкретного юзера перед каждым вашим сообщением добавлялась мапа {processed user id: 12345} Подстановка параметров: писать Logger.debug("Transaction #{} has failed with message '{}'", transaction.getId(), e.getMessage()) гораздо удобнее, чем писать System.out.ptintln("Transaction #" + transaction.getId() + " has failed with message '" + e.getMessage() + "'"). Кроме удобства, это позволяет не конкатенировать строки, если уровень логирования выше самого сообщения (т.е. при уровне INFO сообщения с уровнем DEBUG не будут тратить ресурсы на конкатенацию) и группировать лог-сообщения по шаблону (искать в логах вместо просто слова "transaction" конкретный шаблон). Всем этим занимается библиотека логирования, и она сильно упрощает жизнь, когда нужно перейти от одной модели к другой, например, когда логи возле приложения хранить стало нецелесообразно, для переключения на удаленный сервер достаточно подключить новый аппендер и перезапустить приложение. Кроме того, существует ситуация, когда логов настолько много, что I/O не успевает справляться - о проблемах такого рода, как правило, не думают вплоть до их появления, а в библиотеках (я надеюсь) некоторые предусмотрительные шаги уже сделаны (например, logback совершенно точно по умолчанию пытается добавить сообщение пять раз на тот случай, если что-то пошло не так).

Ответ 2



По сути, выше уже всё было сказано, добавлю ещё один практический аспект. Консоль имеет определённую емкость. И, например, если она равна 300 строк, то в случае, если в неё запишутся 500 строк, начальные 200 строк вы уже не увидите. Можно, конечно, увеличить размер буфера консоли, но тогда придётся его увеличивать постоянно, а это не лучший вариант. Особенно для большого проекта, где логи записываются практически непрерывно, и логируется большой объём данных.

Простой способ объединения массивов строк

#java #массивы #строки


Добрый день!

Мне нужно объединить два массива строкового типа, каким простым способом я могу сделать это?

String[] bothArray(String[] first, String[] second) {
    return ??;
}

    


Ответы

Ответ 1



Если разрешено использовать Java8, то можно воспользоваться классом Stream и лямбдами: import java.util.Arrays; import java.util.stream.Stream; // . . . String[] bothArray(final String[] first, final String[] second) { return Stream.concat(Stream.of(first), Stream.of(second)).toArray(String[]::new); } Компактно, красиво и не требует внешних компонентов.

Ответ 2



С помощью библиотеки Apache Commons: String[] both = (String[])ArrayUtils.addAll(first, second); отсюда Другой вариант public static String[] combine(String[] a, String[] b){ int length = a.length + b.length; String[] result = new String[length]; System.arraycopy(a, 0, result, 0, a.length); System.arraycopy(b, 0, result, a.length, b.length); return result; } источник с примерами Еще один вариант для всех типов. Тут можно не только примитивные типы использовать, а так же объектов public T[] concatenate (T[] a, T[] b) { int aLen = a.length; int bLen = b.length; @SuppressWarnings("unchecked") T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen+bLen); System.arraycopy(a, 0, c, 0, aLen); System.arraycopy(b, 0, c, aLen, bLen); return c; } источник

Ответ 3



И еще один вариант. (Редко вижу его упоминание) String[] array; StringBuilder newStr = new StringBuilder(); for(String data: array){ newStr.append(data); } return newStr.toString();

Private наследование

#c++ #ооп


Для чего нужно наследование с описателем доступа private, если все поля базового
класса станут недоступными?
    


Ответы

Ответ 1



Именно для того, чтобы все члены базового класса не были доступны снаружи (были доступны только изнутри класса, или друзьям класса). Наследование мало чем отличается от аггрегации, и class A : private B { ... }; аналогично class A { private: B b; };. Одна в отличие от private: B b;, при наследовании функции B можно вызывать как члены своего класса, т.е. не b.f(), а просто f(). Также можно унаследоваться от абстрактного класса, и переопределить его методы, не показывая все эти делати наружу, например: struct Callback { virtual void done() = 0; }; void run(Callback* b); class Cls : private Callback { public: void some() { run(this); } private: void done() override { ... } };

Ответ 2



Приватное наследование — это по существу композиция, выраженная немного по-другому. При композиции у вас вложенный объект доступен по своему имени, но не виден снаружи. При приватном наследовании вложенный объект «влит» в *this. Вообще, роль наследования — выражать отношение Is-A между классами. То есть, выражать наследование интерфейса, при этом наследование имплементации есть техническая деталь. А приватное наследование именно это и не может, при приватном наследовании наследуется именно имплементация, но не интерфейс. Поэтому практически всегда вместо приватного наследования стоит предпочесть именно композицию: она выражает ту же идею, но явно.

Ответ 3



При приватном наследовании public и protected члены базового класса будут вполне доступны, как приватные члены в производном классе.

Final переменная для анонимного класса

#java


Есть пример кода:

public static void main(String[] args){
    int a=5;
    new Thread(new Runnable(){
        @Override
        public void run() {
            System.out.println(a);
        }
    }).start();
}


Нужно использовать переменную a в анонимном классе, компилятор говорит объявить её
как final.

Почему она должна быть final?
    


Ответы

Ответ 1



Это ограничение, которое ввели разработчики спецификации: при создании анонимного класса происходит захват объектов по значению, а не по ссылке. В анонимном классе создаются закрытые поля, в которые копируются значения переданных переменных. То есть по сути реализована эмуляция замыканий. Добавление модификатора final как бы говорит программисту о том, что при использовании такого рода замыканий не будут наблюдаться побочные эффекты (представьте, что вы передали в созданный объект анонимного класса переменную, а затем изменили её "снаружи" - вы в праве ожидать, что это изменение отразится и внутри замыкания, но это не так в силу пресловутой эмуляции; однако изменение внутреннего состояния mutable объектов будет видно и там и там). Для реализации полноценных замыканий необходимо расширять жизненный цикл захватываемых объектов (это касается объектов, расположенных в стеке, которые при выходе из области видимости, в которой они объявлены, уничтожаются). Почему это не реализовано до сих пор? Для такого рода реализации необходимо внести серьезное изменение в саму архитектуру JVM. Такого рода изменения достаточно сложно внедрить по определенным причинам: потребуется много усилий для внесения изменений не только со стороны Oracle, но и со стороны сторонних разработчиков (дебаггеры, обфускаторы, IDE, компиляторы и т.д.). Внесение такого изменения может привести к утрате обратной совместимости, что отразится на множестве уже существующих приложений. Изменение может отразиться на других языках/платформах, завязанных на среде JVM. В Java 8 ввели понятие effectively final - это переменные, которые не имеют модификатора final, но могут использоваться в анонимных классах и лямбда-выражениях. Переменная будет effectively final, если после её определения она не изменяется. Соответственно на Java 8 ваш код будет скомпилирован. Дополнительные ссылки для более подробного ознакомления: Accessing Members of an Enclosing Class, Why are only final variables accessible in anonymous class? Does Java 8 Support Closures?

Ответ 2



Ваш код создаёт поток, поток запускается на выполнение, а вызвавшая поток функция (в данном случае main) может завершиться. При завершении функции все её локальные переменные, в том числе и i исчезнут, выделенная под них память возвратится системе. Следовательно, поток не должен иметь доступ к локальным переменным. Но! Если у переменной Вы укажете квалификатор final, то Вы, фактически, говорите компилятору, что это не переменная, а константа. Компилятор будет уверен, что после инициализации эта константа не изменится, поэтому со спокойной совестью вместо прямого обращения к переменной поставит внутри кода потока её копию.

Консоль Sublime Text 3

#node.js #cmd #sublime_text


Подскажите, пожалуйста, как настроить консоль в sublimetext3, чтобы не открывать
стандартную консоль (cmd) в Windows?
    


Ответы

Ответ 1



В обзоре могут содержаться субъективные суждения, основанные на опыте работы с плагинами для Sublime Text. Протестировано на Windows 32-bit 10.0.14393, Отключён контроль учётных записей, Sublime Text Build 3126. Вообще в Sublime Text по моему вероятностному суждению примерно треть плагинов совсем не работают после установки. Но расписанные в обзоре лично у меня функционируют, что доказывается скринкастами. По причине того, что использую Windows, не рассмотрены такие решения, как Tint и fish-shell. Если не упомянул что-то ещё, можете добавить. Терминология В данном обзоре встроенная консоль Windows называется «консолью» или «внешней консолью» в зависимости от контекста. Согласно автору программы ConEmu называть её cmd.exe не совсем корректно: В Windows есть встроенный терминал (или “консольное окно”) которое часто ошибочно называют “cmd.exe”. Нажмите Win+R и запустите, например, “powershell.exe”. Среди запущенных процессов не будет “cmd.exe”. В разных версиях Windows консольное окно создают разные процессы, в актуальных – это “conhost.exe”. Не ‘cmd.exe’, а просто ‘консоль’! 0. Не работающее решение 1. SublimePTY Страница плагина. Разработка давно прекращена. 1. Для запуска отдельных команд Для Sublime Text пишут плагины, облегчающие запуск только отдельных команд только для определённых инструментов программирования. Например, команды Git проще запускать с помощью плагинов Git, SideBar Git и Easygit (Не загружайте Easygit через Package Control, он не будет работать! Установите плагин вручную по ссылке). Так как в вопросе указана метка Node.js, приведу в пример плагин npm. 1. npm Плагин, благодаря которому можно запускать многие команды npm — пакетного менеджера Node.js. 1. Демонстрация 2. Недостатки Баги. Не запускается ряд команд. 2. Эмуляция терминала прямо в Sublime Text Общая оценка Все решения хорошие, пользуюсь ими, но полностью внешние терминалы они не заменяют. 1. Glue 1. Оценка Использую иногда. 2. Демонстрация 3. Установка и настройка Скачиваем плагин через Package Control → В открытом файле проекта Ctrl+Shift+P → Glue - Launch. Или же кликаете правой кнопкой мыши по папке в сайдбаре, в выпадающем меню выбираете Open Glue Terminal. Откроется quick panel, куда следует вводить команды: Появится файл terminal.glue. Без него никак, если мешает, можете добавить расширение glue в .gitignore, .hgignore или другой файл, который используется для игнорирования директорий/файлов в Вашей системе контроля версий. Чтобы в выводе была хоть какая-то подсветка, скачиваем плагин PowerShell → настраиваем для расширения glue синтаксис PowerShell. 4. Достоинства Не нужно выходить из Sublime Text, чтобы запускать команды, Достаточно многофункциональный плагин, Удобнее осуществлять навигацию по output, если тот большой, во вкладке, нежели в консоли. 5. Недостатки Разработка прекращена, шанс, что ответят на Ваш багрепорт, минимален, А багов, которые не воспроизводятся в других терминалах, достаточно. Так, не рекомендовал бы пушить изменения Git через Glue. Лимиты. Cash в Glue не запустишь. 6. Дополнительные ссылки Обзор Glue, Собственные команды Glue, Инструкция по созданию и использованию алиасов в Glue. 2. SublimeREPL Позволяет запускать REPL консоль для многих языков программирования во вкладке Sublime Text. В примере этого ответа написано, как настроить SublimeREPL для PowerShell. 1. Оценка Пользуюсь часто, но иногда вынужден прибегать к другим терминалам. 2. Демонстрация 3. Установка и настройка Помимо самого SublimeREPL устанавливаем также плагины Suricate и PowerShell для настройки команды SublimeREPL и подсветки синтаксиса соответственно. Инструкция по настройке команд в Suricate. Ctrl+Shift+P → SublimeREPL: PowerShell → если у Вас русская версия операционной системы, может вылезти всплывающее окно с примерно следующей ошибкой: error: UnicodeDecodeError('utf-8', b'C:\\Users\\\x8a\xae\xe2', 9, 10, 'invalid start byte') В таком случае перейдите в файл Default.suricate-profile (как — см. инструкцию, всё, что в ней есть, я буду опускать в данном ответе) → и вставьте следующий json-массив. Не путайтесь в JSON-синтаксисе, следите за правильной расстановкой кавычек, скобок и запятых. // SublimeREPL PowerShell "sublime_repl_powershell": { "caption": "SublimeREPL: PowerShell", "keys": ["super+alt+p"], "call": "sublime.repl_open", "args": { "type": "powershell", "encoding": "utf8", "cmd": ["powershell", "-"], "cwd": "$file_path", "external_id": "powershell", "syntax": "Packages/PowerShell/Support/PowerShellSyntax.tmLanguage" } }, 4. Параметры аргументов type — тип. Означает, что во вкладке запустится консоль PowerShell, а не какая-либо другая вроде Python или Node. encoding — кодировка. cmd — запускаем PowerShell в консоли Windows. cwd — указываем системную переменную. $file_path означает, что SublimeREPL PowerShell запустится в папке файла, находясь в котором мы запустили SublimeREPL PowerShell. external_id — Во-первых, данным параметром определяется, как будет называться вкладка с PowerShell. Если оставить параметру пустое значение, "external_id": "", то во вкладке будет указан полный путь к файлу powershell.exe: Мы назвали вкладку powershell, но можно по-любому. Если подставите значение sashatriumph, ничего не должно поломаться: Во-вторых, значение параметра external_id является именем файла, где хранится история команд, когда-либо вводимых Вами в SublimeREPL PowerShell. Файл c расширением .db располагается по пути Packages/User/.SublimeREPLHistory. syntax — относительный путь к файлу синтаксиса для подсветки вкладки SublimeREPL PowerShell, начиная с Packages. 5. Достоинства Не нужно выходить из Sublime Text, чтобы запускать команды, Удобнее осуществлять навигацию по output, если тот большой, во вкладке, нежели в консоли. Особенно нравится, что запоминаются все команды, которые когда-либо вводили. 6. Недостатки Кодировки. Если приходится работать не только с английскими символами, ещё замучаетесь бороться с багами. Разработка прекращена, шанс, что ответят на Ваш багрепорт, минимален, Не всё, что работает в PowerShell, работает в SublimeREPL PowerShell. Например, Cash в Glue не запустишь. SublimeREPL PowerShell не получится заменить терминал полноценно. 7. Дополнительная ссылка Документация SublimeREPL. 3. Terminality В примере показан вывод для Python, но можно использовать как консоль и для других языков программирования, включая отсутствующие по умолчанию в плагине. 1. Оценка Использую для обучения Python и PHP. 2. Демонстрация 3. Установка и настройка Загружаем плагин через Package Control → открываем файл hangman.py, вывод из которого собираемся осуществить, → Ctrl+Shift+P → Terminality: Browse Commands... → Run hangman.py — Run hangman.py as Python 2.7 document → видим результат в новой вкладке, включая время, потраченное на компиляцию, в сантисекундах. Обратите внимание, что пунктом меню Run hangman.py as Python3 запускается команда python3, при выборе Run hangman.py — команда python. Даже когда у Вас установлен Python 3, а не Python 2, если исполняемый файл Python называется python.exe, а не python3.exe, выбирайте Run hangman.py — Run hangman.py as Python 2.7 document. 4. Достоинства Не нужно выходить из Sublime Text, чтобы запускать команды, Удобнее осуществлять навигацию по output, если тот большой, во вкладке, нежели в консоли. Активно поддерживается разработчиками. 5. Недостатки Некоторые баги, которые не воспроизводятся во внешних терминалах. «Although Terminality can run many commands, it is not gurranteed that it can be used for all commands». 6. Дополнительные ссылки Репозиторий плагина, где описываются его возможности, Инструкция по настройке Terminality для не настроенных в плагине нативно языков программирования на примере PHP. 3. Запуск из Sublime Text внешних терминалов Достоинства и недостатки относятся уже к вызываемым в Sublime Text терминалам, а не самому Sublime Text. 1. Консоль/GNOME Terminal 1. Установка и настройка Устанавливаем плагин Suricate. Ctrl+Shift+P → Suricate: Open Terminal Here... → откроется новое окно с консолью для Windows и GNOME Terminal для Linux соответственно в директории с тем файлом, который был у Вас открыт, когда запускали терминал. 2. Параметры и их значения Как выглядит конфигурационный файл Suricate: // Open terminal. "open_terminal_here": { "call": "Suricate.lib.process.spawn", "caption": "Open Terminal Here...", "flags": "Windows|Linux", "args.windows": {"cmd": ["start", "cmd.exe"], "working_dir": "${file_path}"}, "args.linux": {"cmd": ["gnome-terminal"], "working_dir": "${file_path}"}, }, (В оригинальном массиве также есть параметры/значения "group": "launch", |IsFile, "context_menu": true, каковые я опустил в силу того, что считаю их излишними.) flags — параметр, при помощи которого можно задать различные аргументы для операционных систем или систем управления версиями. args.windows и args.linux — параметры запуска терминалов Windows и Linux. Дополнительная ссылка См. данный ответ и ссылки в его конце 2. Запуск любого предпочтительного терминала Для примера возьмём, как запустить Git Bash из Sublime Text. 1. Установка и настройка Устанавливаем плагин Suricate → в файл Default.suricate-profile добавляем следующий код: // Запустить Git Bash "git-bash": { "call": "Suricate.lib.process.spawn", "args.windows": { "cmd": ["C:\\Program Files\\Git\\git-bash.exe"], "working_dir": "${file_path}" }, "caption": "Git Bash", "keys": ["+super+keypad3"], }, Ctrl+Shift+P → Suricate: Git Bash → должен открыться Git Bash в директории с тем файлом, который был у Вас открыт, когда запускали Git Bash из Sublime Text. 2. Дополнительная ссылка См. данный ответ и ссылки в его конце 3. Плагин Terminal 1. Описание Кроссплатформенный плагин, позволяющий открывать из Sublime Text любой терминал, который лично Вы считаете наиболее предпочтительным. В Windows по умолчанию запускается PowerShell. После установки плагина доступны 3 варианта запуска: Из command palette, Из контекстного меню сайдбара, Шорткатом. Многим пользователям не нравится, что задействуется сочетание, по умолчанию используемое для переоткрытия последней закрытой вкладки, можете перезаписать шорткат в файле пользовательского кеймапа. Вызываются две команды: open_terminal — открывает терминал в папке, где лежит файл, вкладка с которым была открыта, когда запускали терминал. open_terminal_project_folder — возможно, работает некорректно. Актуальное поведение: Если Вы запустили команду, из файла, который находится в верхней папке Вашего сайдбара или её подпапках, терминал запустится в этой верхней папке. Например, мой сайдбар: Когда я запускаю open_terminal_project_folder, например, из файла E:\Киролайна\SashaFolder\SashaFile.txt, терминал откроется в E:\Киролайна. Но когда Вы запускаете команду из файла, не имеющего отношения к верхней папке Вашего сайдбара — в моём случае E:\Киролайна, — поведение команды open_terminal_project_folder аналогично поведению open_terminal. 2. Настройка Вы можете указывать параметры запуска Вашего терминала. Положим, хотите всегда запускать консольный эмулятор cmder только из директории E:\SashaSublime. Для упрощения работы с настройками Sublime Text скачиваем плагин Preferences Editor. Ctrl+Shift+P → Edit Preferences: Edit Settings... → Terminal → terminal → в открывшуюся quick panel вставляете путь к исполняемому файлу cmder.exe вместе с именем файла, например, E:\Chocolatey\tools\cmder\Cmder.exe → Enter. Далее Ctrl+Shift+P → Edit Preferences: Edit Settings... → Terminal → parameters → между квадратными скобками вставляем "/START", "E:\\SashaSublime" → Enter. Обратите внимание, что если значения заключены в [квадратные скобки], необходимо экранировать слэши: E:\Chocolatey\tools\cmder\Cmder.exe, но E:\\SashaSublime. Теперь после запуска любой из команд — open_terminal либо open_terminal_project_folder должен открыться Cmder.exe в папке E:\SashaSublime. Также предусмотрена возможность одним шорткатом запускать один терминал со своими параметрами, вторым хоткеем запускать другой терминал с другими параметрами и т. д. Читаем здесь. 3. Дополнительные ссылки Краткое описание плагина Terminal в книге «Sublime Text Power User», Репозиторий плагина на GitHub 4. ConEmu Для лучшей, по мнению пользователей англоязычного Stack Overflow, консоли для Windows есть свой плагин. См. также плагин для Cmder — немного изменённого ConEmu. 1. Описание По умолчанию осуществляется запуск PowerShell в оболочке ConEmu. Как и в плагине Terminal, ConEmu можно запустить из command palette, контекстного меню сайдбара или шорткатом. open_conemu_here — открывает ConEmu в папке, где лежит файл, вкладка с которым была открыта, когда запускали ConEmu. open_conemu_project — возможно, работает некорректно. Всегда открывает ConEmu в верхней папке сайдбара, в моём случае (см. п. 3.3) это E:\Киролайна. 2. Недостатки Разработчик перешёл на MacOS, плагин больше не поддерживается. Баги. я пофиксил, что нашёл, но далеко не факт, что их больше не осталось. 3. Дополнительные ссылки Альтернативный терминал для Windows — статья на Хабрахабре, Официальный сайт ConEmu, Документация ConEmu. 4. Обратное решение — вывод во внешнюю консоль 1. Console Exec 1. Оценка Пользуюсь вместо дефолтных Build System. 2. Описание Плагин выводит результаты Build System во внешнюю консоль, а не встроенную Sublime Text. Это может понадобиться по ряду причин. Если после вывода требуется вводить что-то ещё в консоль , — дефолтным механизмом Build System без дополнительных надстроек не обойтись. Установив же Console Exec и добавив в файл Build System всего одну дополнительную строку, Вы можете и дальше вводить команды. Если пользуетесь плагином Build Next, когда в выводе нет ошибок, встроенная панель Build System автоматически закрывается. Использование внешней панели средствами Console Exec избавляет от данной проблемы. Встроенная панель не поддерживает некоторые средства программирования как Pyglet. В панели Build System неудобна навигация. Увеличишь панель Build System — не будет видно содержимого вкладок, уменьшишь — вывода в панель. Выводя результаты во внешнюю консоль, при закрытии Sublime Text внешняя консоль остаётся открытой — дополнительное удобство. 3. Демонстрация 4. Настройка После установки плагина достаточно добавить в файл Build System одну дополнительную строку: "target": "console_exec" Пример для Python. Tools → Builds System → New Build System... → вставляем следующий код и сохраняем файл, например, под именем SashaPythonExec.sublime-build: { "cmd": ["python", "-u", "$file"], "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", "selector": "source.python", "target": "console_exec" } Как создавать и настроить автоматический выбор Build System, подробно рассмотрено по дополнительным ссылкам. Во вкладке со скриптом на Python Ctrl+Shift+P → Build With: SashaPythonExec → смотрим результат. 5. Дополнительные ссылки Документация по использованию Build System в Sublime Text, Описание Build System в книге «Sublime Text Power User», Некоторые готовые Build System для компьютерных языков и инструментов программирования, Настройка автоматического выбора Build System. 2. Send to Shell В Sublime Text существуют плагины, отправляющие во внешний терминал выделенный или скопированный текст, как SendText и SendREPL. Тот же принцип действия у плагина Send to Shell, отправляющего скопированный текст в IPython — интерактивную оболочку для Python, составляющую Jupyter. 1. Демонстрация 2. Установка Как настроить плагин для отправки скопированного текста на ConEmu в режиме PowerShell. Скачиваем и устанавливаем последнюю версию Python, если Python ещё не установлен в системе. Устанавливаем Jupyter, проще всего, запустив в терминале команду pip install jupyter. Устанавливаем через Package Control PyWin32 — набор расширений Python для доступа ко многим функциям Windows API. Устанавливаем через Package Control плагин Preferences Editor для упрощения работы с файлами настроек Sublime Text. Устанавливаем через Package Control плагин Send to Shell. 3. Настройка Задаём системную переменную PATH, указав в качестве значения путь к файлу ConEmu.exe, для меня это C:\Program Files\ConEmu. Запускаем ConEmu → Super+Alt+P → Startup → задаём параметру Specifed named task значение {Shells::PowerShell}: В Sublime Text 3 Ctrl+Shift+P → Edit Preferences: Edit Settings... → SendToShell → powershell_startup → в открывшееся поле вместо powershell вписываем conemu. Ctrl+Shift+P → Edit Preferences: Edit Settings... → SendToShell → window_title → в открывшееся поле вместо Windows PowerShell вписываем заголовок вкладки ConEmu: у меня это powershell (Admin). Опционально предлагаю установить плагин CopyOnSelect, — пусть по первому времени он вызвать неудобства, — копирующий в буфер обмена выделенный текст. Задержка между выделением текста и его копированием в данном плагине составляет секунду, и автор не рекомендует её сильно уменьшать из-за возможных проблем с работой Clipboard-менеджеров. Настройка окончена. Выделяем кусок скрипта на Python для отправки в ConEmu → копируем его (а с плагином CopyOnSelect достаточно только выделить) → запускаем команду sendtoshell {"how": "paste_selection"}, — по умолчанию сочетанием клавиш Ctrl+Shift+Enter, — в ConEmu пишем команду ipython, а затем %paste. Можно было, конечно, написать плагин так, чтобы пользователь совершал поменьше действий. 4. Недостатки Баги в установке связи плагина с терминалом. 5. Дополнительные ссылки Оболочка IPython как инструмент системного администратора (python freebsd shell), IPython: замена стандартного Python shell. 5. Поиск плагинов Если описанные в обзоре плагины не удовлетворяют Вашим задачам, помимо обычного поиска в Google порекомендовал бы осуществить поиск примерно по следующим ключевым словам и меткам на сайте Package Control: terminal, build system, console, repl, shell.