diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..253bcb7 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..6602f60 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,58 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.experimental }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + emacs-version: + - 26.3 + - 27.2 + - 28.2 + - 29.4 + - 30.1 + experimental: [false] + include: + - os: ubuntu-latest + emacs-version: snapshot + experimental: true + - os: macos-latest + emacs-version: snapshot + experimental: true + - os: windows-latest + emacs-version: snapshot + experimental: true + exclude: + - os: macos-latest + emacs-version: 26.3 + - os: macos-latest + emacs-version: 27.2 + + steps: + - uses: actions/checkout@v6 + + - uses: jcs090218/setup-emacs@master + with: + version: ${{ matrix.emacs-version }} + + - uses: emacs-eask/setup-eask@master + with: + version: 'snapshot' + + - name: Run tests + run: + make ci diff --git a/.gitignore b/.gitignore index 0ef71f7..08dcc82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ *~ .cask/ +.eask/ +/dist +*.elc .vagrant/ + +# OS generated +.DS_Store diff --git a/Eask b/Eask new file mode 100644 index 0000000..6e09991 --- /dev/null +++ b/Eask @@ -0,0 +1,21 @@ +;; -*- mode: eask; lexical-binding: t -*- + +(package "pythonic" + "0.2" + "Utility functions for writing pythonic emacs package") + +(website-url "https://github.com/proofit404/pythonic") +(keywords "convenience" "pythonic") + +(package-file "pythonic.el") + +(script "test" "echo \"Error: no test specified\" && exit 1") + +(source 'gnu) +(source 'melpa) + +(depends-on "emacs" "25.1") +(depends-on "s") +(depends-on "f") + +(setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e92a368 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +EMACS ?= emacs +EASK ?= eask + +.PHONY: clean checkdoc lint package install compile test + +ci: clean package install compile + +package: + @echo "Packaging..." + $(EASK) package + +install: + @echo "Installing..." + $(EASK) install + +compile: + @echo "Compiling..." + $(EASK) compile + +test: + @echo "Testing..." + $(EASK) test ert ./test/*.el + +checkdoc: + @echo "Run checkdoc..." + $(EASK) lint checkdoc + +lint: + @echo "Run package-lint..." + $(EASK) lint package + +clean: + $(EASK) clean all diff --git a/README.markdown b/README.markdown index fae13b8..40c13b8 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,9 @@ -# Pythonic [![MELPA](http://www.melpa.org/packages/pythonic-badge.svg)](http://www.melpa.org/#/pythonic) [![MELPA Stable](https://stable.melpa.org/packages/pythonic-badge.svg)](https://stable.melpa.org/#/pythonic) +[![MELPA](https://melpa.org/packages/pythonic-badge.svg)](https://melpa.org/#/pythonic) +[![MELPA Stable](https://stable.melpa.org/packages/pythonic-badge.svg)](https://stable.melpa.org/#/pythonic) + +# Pythonic + +[![CI](https://github.com/pythonic-emacs/pythonic/actions/workflows/test.yml/badge.svg)](https://github.com/pythonic-emacs/pythonic/actions/workflows/test.yml) Utility functions for writing pythonic emacs package. @@ -120,3 +125,24 @@ Activate python virtual environment. Tramp paths are supported. ### pythonic-deactivate Deactivate python virtual environment. + +## Project settings + +You can change the default docker-compose file name and set a default +service name to run the pythonic commands. + +Add these lines to the `.dir-locals.el` file in the project root +directory. + +```lisp +((python . ((pythonic-docker-compose-filename . "local.yml") + (pythonic-docker-compose-service-name . "web")))) +``` + +You can change the interpreter that pythonic uses. This is especially useful when you have set your `python-shell-interpreter` to something like `jupyter-console`. By default, it'll use `python-shell-interpreter`. + +To change it: + +```lisp +(setq pythonic-interpreter "python") +``` diff --git a/pythonic.el b/pythonic.el index cd5eb93..83611aa 100644 --- a/pythonic.el +++ b/pythonic.el @@ -1,11 +1,12 @@ -;;; pythonic.el --- Utility functions for writing pythonic emacs package. -*- lexical-binding: t; -*- +;;; pythonic.el --- Utility functions for writing pythonic emacs package -*- lexical-binding: t; -*- -;; Copyright (C) 2015-2018 by Artem Malyshev +;; Copyright (C) 2015-2021 by Artem Malyshev ;; Author: Artem Malyshev ;; URL: https://github.com/proofit404/pythonic -;; Version: 0.1.1 -;; Package-Requires: ((emacs "25") (s "1.9") (f "0.17.2")) +;; Version: 0.2 +;; Package-Requires: ((emacs "25.1") (s "1.9") (f "0.17.2")) +;; Keywords: convenience pythonic ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -32,6 +33,10 @@ (require 's) (require 'f) +(defgroup pythonic nil + "Utility functions for writing pythonic emacs package." + :group 'python) + ;;; Connection predicates. @@ -41,7 +46,8 @@ (defun pythonic-remote-p () "Determine remote virtual environment." - (tramp-tramp-file-p (pythonic-aliased-path default-directory))) + (and (tramp-tramp-file-p (pythonic-aliased-path default-directory)) + t)) (defun pythonic-remote-docker-p () "Determine docker remote virtual environment." @@ -51,7 +57,7 @@ (defun pythonic-remote-ssh-p () "Determine ssh remote virtual environment." (and (pythonic-remote-p) - (s-equals-p (pythonic-remote-method) "ssh"))) + (member (pythonic-remote-method) '("ssh" "sshx")))) (defun pythonic-remote-vagrant-p () "Determine vagrant remote virtual environment." @@ -127,7 +133,7 @@ Take FILENAME from the perspective of the localhost and translate it to the FILENAME Python process can read. Python can be running locally or remotely. FILENAME can have local or tramp format. Result will have local format." - (let ((alias (pythonic-aliased-path filename))) + (let ((alias (pythonic-aliased-path (expand-file-name filename)))) (if (tramp-tramp-file-p alias) (tramp-file-name-localname (tramp-dissect-file-name alias)) alias))) @@ -152,7 +158,15 @@ format." ;;; Docker Compose. -(defvar pythonic-docker-compose-filename "docker-compose.yml") +(defcustom pythonic-docker-compose-filename "docker-compose.yml" + "File name of the docker-compose project file." + :type 'string + :safe 'stringp) + +(defcustom pythonic-docker-compose-service-name nil + "Name of the default service to execute commands." + :type 'string + :safe 'stringp) (defvar pythonic-read-docker-compose-file-code " from __future__ import print_function @@ -207,6 +221,7 @@ print(json.dumps(yaml.safe_load(open(sys.argv[-1], 'r')))) (defun pythonic-set-docker-compose-alias () "Build alias string for current docker-compose project." + (hack-dir-local-variables-non-file-buffer) (unless (or (tramp-tramp-file-p default-directory) (pythonic-has-alias-p default-directory)) @@ -219,7 +234,11 @@ print(json.dumps(yaml.safe_load(open(sys.argv[-1], 'r')))) ;; should appears once in the selection and all volumes ;; should be added to the alias list. (volume (if (< 1 (length volumes)) - (assoc (completing-read "Service: " (mapcar 'car volumes) nil t) volumes) + (assoc + (if pythonic-docker-compose-service-name + pythonic-docker-compose-service-name + (completing-read "Service: " (mapcar #'car volumes) nil t)) + volumes) (car volumes))) (service (car volume)) (sub-project (f-join project (cadr volume))) @@ -235,16 +254,20 @@ print(json.dumps(yaml.safe_load(open(sys.argv[-1], 'r')))) ;;; Processes. +(defvar pythonic-interpreter python-shell-interpreter + "Interpreter to use for pythonic process calls.") + (cl-defun pythonic-call-process (&key file buffer display args cwd) "Pythonic wrapper around `call-process'. FILE is the input file. BUFFER is the output destination. DISPLAY specifies to redisplay BUFFER on new output. ARGS is the list of + arguments passed to `call-process'. CWD will be working directory for running process." (let ((default-directory (pythonic-aliased-path (or cwd default-directory)))) (python-shell-with-environment - (apply 'process-file python-shell-interpreter file buffer display args)))) + (apply #'process-file pythonic-interpreter file buffer display args)))) (cl-defun pythonic-start-process (&key process buffer args cwd filter sentinel (query-on-exit t)) "Pythonic wrapper around `start-process'. @@ -258,7 +281,7 @@ function if necessary. QUERY-ON-EXIT will be corresponding process flag." (let ((default-directory (pythonic-aliased-path (or cwd default-directory)))) (python-shell-with-environment - (let ((process (apply 'start-file-process process buffer python-shell-interpreter args))) + (let ((process (apply #'start-file-process process buffer pythonic-interpreter args))) (when filter (set-process-filter process filter)) (when sentinel @@ -273,7 +296,8 @@ process flag." (defun pythonic-activate (virtualenv) "Activate python VIRTUALENV." (interactive "DEnv: ") - (setq python-shell-virtualenv-root (pythonic-python-readable-file-name virtualenv))) + (setq python-shell-virtualenv-root + (and virtualenv (pythonic-python-readable-file-name virtualenv)))) ;;;###autoload (defun pythonic-deactivate ()