commit 56871dbd4c1a1af3f0d1624f4858e9be67a89f7e (HEAD, refs/remotes/origin/master) Author: Dmitry Gutov Date: Mon May 27 01:23:30 2024 +0300 * lisp/progmodes/project.el: Up xref dependency and bump the version diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index c57c16073b9..dceca2eab48 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1,8 +1,8 @@ ;;; project.el --- Operations on the current project -*- lexical-binding: t; -*- ;; Copyright (C) 2015-2024 Free Software Foundation, Inc. -;; Version: 0.10.0 -;; Package-Requires: ((emacs "26.1") (xref "1.4.0")) +;; Version: 0.11.0 +;; Package-Requires: ((emacs "26.1") (xref "1.7.0")) ;; This is a GNU ELPA :core package. Avoid functionality that is not ;; compatible with the version of Emacs recorded above. commit cef848fe5f355ca34abc176739d0ace835b12eed Author: Dmitry Gutov Date: Mon May 27 01:21:40 2024 +0300 * lisp/progmodes/xref.el: Bump the version to 1.7.0 diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index af77e860020..0025f1f9479 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -1,7 +1,7 @@ ;;; xref.el --- Cross-referencing commands -*-lexical-binding:t-*- ;; Copyright (C) 2014-2024 Free Software Foundation, Inc. -;; Version: 1.6.3 +;; Version: 1.7.0 ;; Package-Requires: ((emacs "26.1")) ;; This is a GNU ELPA :core package. Avoid functionality that is not commit 74b8043e60dde6710d0ba413278c2cb36a84f8f2 Author: Eli Zaretskii Date: Sun May 26 19:41:30 2024 +0300 Prevent crashes due to redisplay while realizing the default face * src/xfaces.c (Finternal_merge_in_global_face) (realize_default_face): Prevent redisplay while the default face is being realized. (Bug#71176) diff --git a/src/xdisp.c b/src/xdisp.c index 7a00b297d61..47675fcc80a 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13377,8 +13377,10 @@ echo_area_display (bool update_frame_p) w = XWINDOW (mini_window); f = XFRAME (WINDOW_FRAME (w)); - /* Don't display if frame is invisible or not yet initialized. */ - if (!FRAME_REDISPLAY_P (f) || !f->glyphs_initialized_p) + /* Don't display if frame is invisible or not yet initialized or + if redisplay is inhibited. */ + if (!FRAME_REDISPLAY_P (f) || !f->glyphs_initialized_p + || !NILP (Vinhibit_redisplay)) return; #ifdef HAVE_WINDOW_SYSTEM diff --git a/src/xfaces.c b/src/xfaces.c index 5192b22ce0a..258fbc52e64 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -4246,6 +4246,12 @@ Default face attributes override any local face attributes. */) /* This can be NULL (e.g., in batch mode). */ if (oldface) { + /* In some cases, realize_face below can call Lisp, which could + trigger redisplay. But we are in the process of realizing + the default face, and therefore are not ready to do display. */ + specpdl_ref count = SPECPDL_INDEX (); + specbind (Qinhibit_redisplay, Qt); + /* Ensure that the face vector is fully specified by merging the previously-cached vector. */ memcpy (attrs, oldface->lface, sizeof attrs); @@ -4291,6 +4297,8 @@ Default face attributes override any local face attributes. */) gvec[LFACE_BACKGROUND_INDEX]); Fmodify_frame_parameters (frame, arg); } + + unbind_to (count, Qnil); } } @@ -5959,7 +5967,13 @@ realize_default_face (struct frame *f) eassert (lface_fully_specified_p (XVECTOR (lface)->contents)); check_lface (lface); memcpy (attrs, xvector_contents (lface), sizeof attrs); + /* In some cases, realize_face below can call Lisp, which could + trigger redisplay. But we are in the process of realizing + the default face, and therefore are not ready to do display. */ + specpdl_ref count = SPECPDL_INDEX (); + specbind (Qinhibit_redisplay, Qt); struct face *face = realize_face (c, attrs, DEFAULT_FACE_ID); + unbind_to (count, Qnil); #ifndef HAVE_WINDOW_SYSTEM (void) face; commit c593441ab009fb7068f055cda0af1f9fafd2f600 Author: Stefan Kangas Date: Sun May 26 15:25:21 2024 +0200 Remove Emacs 19 compat code in mm-util.el * lisp/gnus/mm-util.el (mm-preferred-coding-system): Remove Emacs 19 compat code. diff --git a/lisp/gnus/mm-util.el b/lisp/gnus/mm-util.el index 0e4bbbe650f..8ee1eab367b 100644 --- a/lisp/gnus/mm-util.el +++ b/lisp/gnus/mm-util.el @@ -399,9 +399,7 @@ non-nil." (set-buffer-multibyte nil)) (defun mm-preferred-coding-system (charset) - ;; A typo in some Emacs versions. - (or (get-charset-property charset 'preferred-coding-system) - (get-charset-property charset 'prefered-coding-system))) + (get-charset-property charset 'preferred-coding-system)) ;; Mule charsets shouldn't be used. (defsubst mm-guess-charset () commit 34fc71c004b6e0ae787de4889eca2d1e413103f2 Author: Michael Heerdegen Date: Sun May 12 19:55:30 2024 +0200 Further tweak pp code printing This fixes an aspect of Bug#70868. * lisp/emacs-lisp/pp.el (pp--insert-lisp): Print characters with `prin1-char'. In all other cases consistently print with `prin1'. diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el index f89807c37be..d578e685ca9 100644 --- a/lisp/emacs-lisp/pp.el +++ b/lisp/emacs-lisp/pp.el @@ -495,15 +495,12 @@ the bounds of a region containing Lisp code to pretty-print." ;; Print some of the smaller integers as characters, perhaps? (integer (if (<= ?0 sexp ?z) - (let ((print-integers-as-characters t)) - (princ sexp (current-buffer))) - (princ sexp (current-buffer)))) + (princ (prin1-char sexp) (current-buffer)) + (prin1 sexp (current-buffer)))) (string (let ((print-escape-newlines t)) (prin1 sexp (current-buffer)))) - (symbol - (prin1 sexp (current-buffer))) - (otherwise (princ sexp (current-buffer))))) + (otherwise (prin1 sexp (current-buffer))))) (defun pp--format-vector (sexp) (insert "[") commit 3ea451042a34a44da94176f27ea354e6823e68ee Author: Naofumi Yasufuku Date: Sun May 26 17:53:42 2024 +0900 Fix --enable-checking build with macOS clang 15.0.0 search.c:3428:7: error: call to undeclared library function 'free' ... configure:9131: checking for C compiler version configure:9140: gcc --version >&5 Apple clang version 15.0.0 (clang-1500.3.9.4) Target: arm64-apple-darwin23.5.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin * src/search.c: Include stdlib.h for free(), and stdio.h for open_memstream(), fclose(). Copyright-paperwork-exempt: yes diff --git a/src/search.c b/src/search.c index b092d5b7fef..3c07933b5da 100644 --- a/src/search.c +++ b/src/search.c @@ -21,6 +21,9 @@ along with GNU Emacs. If not, see . */ #include +#include +#include + #include "lisp.h" #include "character.h" #include "buffer.h" commit 236034a24d0e93e1796224e2ff4a14819fcfd559 Author: Mattias Engdegård Date: Sun May 26 11:13:50 2024 +0200 Clean up legacy bytecode loading Complete some unfinished work from the elimination of lazy bytecode loading in 9bcc9690a8: remove code which became unreachable by that reform. This simplifies some of the lower-level parts of the reader which helps performance somewhat. * src/doc.c (read_bytecode_pointer, read_bytecode_char) (read_doc_string): Remove. (get_doc_string): Remove last argument, all callers adapted. Simplify. * src/lread.c (readbyte_for_lambda, readbyte_from_string) (readbyte_for_lambda, readbyte_from_string): Remove. (readchar, unreadchar): Remove unused code paths for Qlambda and cons arguments. (bytecode_from_rev_list): Remove last use of a quirky code path, decoding force-loaded lazy bytecode explicitly. diff --git a/src/doc.c b/src/doc.c index 36633a920c6..f516db3bbcc 100644 --- a/src/doc.c +++ b/src/doc.c @@ -74,24 +74,8 @@ along with GNU Emacs. If not, see . */ static char *get_doc_string_buffer; static ptrdiff_t get_doc_string_buffer_size; -static unsigned char *read_bytecode_pointer; - static char const sibling_etc[] = "../etc/"; -/* `readchar' in lread.c calls back here to fetch the next byte. - If UNREADFLAG is 1, we unread a byte. */ - -int -read_bytecode_char (bool unreadflag) -{ - if (unreadflag) - { - read_bytecode_pointer--; - return 0; - } - return *read_bytecode_pointer++; -} - #ifdef USE_ANDROID_ASSETS /* Like `close_file_unwind'. However, PTR is a pointer to an Android @@ -120,15 +104,10 @@ close_file_unwind_android_fd (void *ptr) (e.g. because the file has been modified and the location is stale), return nil. - If UNIBYTE, always make a unibyte string. - - If DEFINITION, assume this is for reading - a dynamic function definition; convert the bytestring - and the constants vector with appropriate byte handling, - and return a cons cell. */ + If UNIBYTE, always make a unibyte string. */ Lisp_Object -get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) +get_doc_string (Lisp_Object filepos, bool unibyte) { char *from, *to, *name, *p, *p1; Lisp_Object file, pos; @@ -312,14 +291,6 @@ Invalid data in documentation file -- %c followed by code %03o", *to++ = *from++; } - /* If DEFINITION, read from this buffer - the same way we would read bytes from a file. */ - if (definition) - { - read_bytecode_pointer = (unsigned char *) get_doc_string_buffer + offset; - return Fread (Qlambda); - } - if (unibyte) return make_unibyte_string (get_doc_string_buffer + offset, to - (get_doc_string_buffer + offset)); @@ -336,16 +307,6 @@ Invalid data in documentation file -- %c followed by code %03o", } } -/* Get a string from position FILEPOS and pass it through the Lisp reader. - We use this for fetching the bytecode string and constants vector - of a compiled function from the .elc file. */ - -Lisp_Object -read_doc_string (Lisp_Object filepos) -{ - return get_doc_string (filepos, 0, 1); -} - static bool reread_doc_file (Lisp_Object file) { @@ -406,7 +367,7 @@ string is passed through `substitute-command-keys'. */) if (FIXNUMP (doc) || CONSP (doc)) { Lisp_Object tem; - tem = get_doc_string (doc, 0, 0); + tem = get_doc_string (doc, 0); if (NILP (tem) && try_reload) { /* The file is newer, we need to reset the pointers. */ @@ -481,7 +442,7 @@ aren't strings. */) if (FIXNUMP (tem) || (CONSP (tem) && FIXNUMP (XCDR (tem)))) { Lisp_Object doc = tem; - tem = get_doc_string (tem, 0, 0); + tem = get_doc_string (tem, 0); if (NILP (tem) && try_reload) { /* The file is newer, we need to reset the pointers. */ diff --git a/src/lisp.h b/src/lisp.h index 534a36499f1..f8d59b1e9fd 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -5273,10 +5273,8 @@ extern void set_initial_environment (void); extern void syms_of_callproc (void); /* Defined in doc.c. */ -extern Lisp_Object read_doc_string (Lisp_Object); -extern Lisp_Object get_doc_string (Lisp_Object, bool, bool); +extern Lisp_Object get_doc_string (Lisp_Object, bool); extern void syms_of_doc (void); -extern int read_bytecode_char (bool); /* Defined in bytecode.c. */ extern void syms_of_bytecode (void); diff --git a/src/lread.c b/src/lread.c index c92b2ede932..233f08b0727 100644 --- a/src/lread.c +++ b/src/lread.c @@ -256,15 +256,13 @@ static Lisp_Object oblookup_considering_shorthand (Lisp_Object, const char *, ptrdiff_t *); -/* Functions that read one byte from the current source READCHARFUN +/* Function that reads one byte from the current source READCHARFUN or unreads one byte. If the integer argument C is -1, it returns one read byte, or -1 when there's no more byte in the source. If C is 0 or positive, it unreads C, and the return value is not interesting. */ -static int readbyte_for_lambda (int, Lisp_Object); static int readbyte_from_file (int, Lisp_Object); -static int readbyte_from_string (int, Lisp_Object); /* Handle unreading and rereading of characters. Write READCHAR to read a character, @@ -278,8 +276,8 @@ static int readbyte_from_string (int, Lisp_Object); /* Same as READCHAR but set *MULTIBYTE to the multibyteness of the source. */ #define READCHAR_REPORT_MULTIBYTE(multibyte) readchar (readcharfun, multibyte) -/* When READCHARFUN is Qget_file_char, Qget_emacs_mule_file_char, - Qlambda, or a cons, we use this to keep an unread character because +/* When READCHARFUN is Qget_file_char or Qget_emacs_mule_file_char, + we use this to keep an unread character because a file stream can't handle multibyte-char unreading. The value -1 means that there's no unread character. */ static int unread_char = -1; @@ -365,12 +363,6 @@ readchar (Lisp_Object readcharfun, bool *multibyte) return c; } - if (EQ (readcharfun, Qlambda)) - { - readbyte = readbyte_for_lambda; - goto read_multibyte; - } - if (EQ (readcharfun, Qget_file_char)) { eassert (infile); @@ -400,20 +392,6 @@ readchar (Lisp_Object readcharfun, bool *multibyte) return c; } - if (CONSP (readcharfun) && STRINGP (XCAR (readcharfun))) - { - /* This is the case that read_vector is reading from a unibyte - string that contains a byte sequence previously skipped - because of #@NUMBER. The car part of readcharfun is that - string, and the cdr part is a value of readcharfun given to - read_vector. */ - readbyte = readbyte_from_string; - eassert (infile); - if (EQ (XCDR (readcharfun), Qget_emacs_mule_file_char)) - emacs_mule_encoding = 1; - goto read_multibyte; - } - if (EQ (readcharfun, Qget_emacs_mule_file_char)) { readbyte = readbyte_from_file; @@ -545,14 +523,6 @@ unreadchar (Lisp_Object readcharfun, int c) read_from_string_index_byte = string_char_to_byte (readcharfun, read_from_string_index); } - else if (CONSP (readcharfun) && STRINGP (XCAR (readcharfun))) - { - unread_char = c; - } - else if (EQ (readcharfun, Qlambda)) - { - unread_char = c; - } else if (FROM_FILE_P (readcharfun)) { unread_char = c; @@ -561,13 +531,6 @@ unreadchar (Lisp_Object readcharfun, int c) call1 (readcharfun, make_fixnum (c)); } -static int -readbyte_for_lambda (int c, Lisp_Object readcharfun) -{ - return read_bytecode_char (c >= 0); -} - - static int readbyte_from_stdio (void) { @@ -638,26 +601,6 @@ readbyte_from_file (int c, Lisp_Object readcharfun) return readbyte_from_stdio (); } -static int -readbyte_from_string (int c, Lisp_Object readcharfun) -{ - Lisp_Object string = XCAR (readcharfun); - - if (c >= 0) - { - read_from_string_index--; - read_from_string_index_byte - = string_char_to_byte (string, read_from_string_index); - } - - return (read_from_string_index < read_from_string_limit - ? fetch_string_char_advance (string, - &read_from_string_index, - &read_from_string_index_byte) - : -1); -} - - /* Signal Qinvalid_read_syntax error. S is error string of length N (if > 0) */ @@ -3517,12 +3460,18 @@ bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun) /* Lazily-loaded bytecode is represented by the constant slot being nil and the bytecode slot a (lazily loaded) string containing the - print representation of (BYTECODE . CONSTANTS). Unpack the - pieces by coerceing the string to unibyte and reading the result. */ + print representation of (BYTECODE . CONSTANTS). */ if (NILP (vec[CLOSURE_CONSTANTS]) && STRINGP (vec[CLOSURE_CODE])) { Lisp_Object enc = vec[CLOSURE_CODE]; - Lisp_Object pair = Fread (Fcons (enc, readcharfun)); + eassert (!STRING_MULTIBYTE (enc)); + /* The string (always unibyte) must be decoded to be parsed. */ + enc = Fdecode_coding_string (enc, + EQ (readcharfun, + Qget_emacs_mule_file_char) + ? Qemacs_mule : Qutf_8_emacs, + Qt, Qnil); + Lisp_Object pair = Fread (enc); if (!CONSP (pair)) invalid_syntax ("Invalid byte-code object", readcharfun); @@ -3772,7 +3721,7 @@ get_lazy_string (Lisp_Object val) && !(pos >= ss->position && pos < ss->position + ss->length)) ss++; if (ss >= ssend) - return get_doc_string (val, 1, 0); + return get_doc_string (val, 1); ptrdiff_t start = pos - ss->position; char *str = ss->string; commit cfd654c418658adacd6ab3717dc1b8cc95d99d44 Author: Joost Kremers Date: Sat May 25 21:55:29 2024 +0200 Update documentation for 'width' slot of vtable ':column' object Bug#71167 diff --git a/doc/misc/vtable.texi b/doc/misc/vtable.texi index 822b1097cd9..6003435385f 100644 --- a/doc/misc/vtable.texi +++ b/doc/misc/vtable.texi @@ -281,11 +281,19 @@ object), or a full @code{vtable-column} object. A The name of the column. @item width -The width of the column. This is either a number (the width of that -many @samp{x} characters in the table's face), or a string on the form -@samp{Xe@var{x}}, where @var{x} is a number of @samp{x} characters, or a -string on the form @samp{Xp@var{x}} (denoting a number of pixels), or a -string on the form @samp{X%} (a percentage of the window's width). +The width of the column. This can be one of the following: + +@table @asis +@item a number @var{n} +@itemx a string of the form @samp{@var{n}ex} +The width of @var{n} @samp{x} characters in the table's face. + +@item a string of the form @samp{@var{n}px} +@var{n} pixels. + +@item a string of the form @samp{@var{n}%} +@var{n} percent of the window's width. +@end table @item min-width This uses the same format as @code{width}, but specifies the minimum commit b241ec0e78f141e7fc22cf3afb11037d14fc028c Author: Lin Sun Date: Mon May 20 06:55:31 2024 +0000 Enhance 'python-shell-send-block' for convenience * lisp/progmodes/python.el (python-shell-send-block): 'python-shell-send-block' will now send block without header by default. * test/lisp/progmodes/python-tests.el (python-test--shell-send-block): Update the test case. (Bug#71083) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index fea52b2f7d6..b5c00385ef3 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -4156,14 +4156,14 @@ interactively." "Send the block at point to inferior Python process. The block is delimited by `python-nav-beginning-of-block' and `python-nav-end-of-block'. If optional argument ARG is non-nil -(interactively, the prefix argument), send the block body without +\(interactively, the prefix argument), send the block body with its header. If optional argument MSG is non-nil, force display of a user-friendly message if there's no process running; this always happens interactively." (interactive (list current-prefix-arg t)) (let ((beg (save-excursion (when (python-nav-beginning-of-block) - (if (null arg) + (if arg (beginning-of-line) (python-nav-end-of-statement) (beginning-of-line 2))) @@ -4172,7 +4172,7 @@ always happens interactively." (python-indent-guess-indent-offset-verbose nil)) (if (and beg end) (python-shell-send-region beg end nil msg t) - (user-error "Can't get code block from current position.")))) + (user-error "Can't get code block from current position")))) (defun python-shell-send-buffer (&optional send-main msg) "Send the entire buffer to inferior Python process. diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index de6a4316758..b41688e9d48 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -7524,7 +7524,7 @@ print('current 3')" (goto-char (point-min)) (should-error (python-shell-send-block) :type 'user-error) (forward-line) - (python-shell-send-block) + (python-shell-send-block t) ;; send block with header (python-tests-shell-wait-for-prompt) (python-shell-with-shell-buffer (goto-char (point-min)) @@ -7533,7 +7533,7 @@ print('current 3')" (should (re-search-forward "current 2" nil t)) (should-not (re-search-forward "current 3" nil t))) (forward-line) - (python-shell-send-block t) ;; send block body only + (python-shell-send-block) ;; send block body only (python-tests-shell-wait-for-prompt) (python-shell-with-shell-buffer ;; should only 1 line output from the block body commit 9ca89cb4834a20bc7d38289046d4d05e2212ba50 Author: kobarity Date: Sun May 26 09:56:29 2024 +0900 ; Fix merge error (bug#71093). diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 79e383a1c1a..fea52b2f7d6 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -800,8 +800,7 @@ sign in chained assignment." ;; c: Collection = {1, 2, 3} ;; d: Mapping[int, str] = {1: 'bar', 2: 'baz'} (,(python-font-lock-assignment-matcher - (python-rx (or line-start ?\;) (* space) - grouped-assignment-target (* space) + (python-rx grouped-assignment-target (* space) (? ?: (* space) (group (+ not-simple-operator)) (* space)) (group assignment-operator))) (1 font-lock-variable-name-face) @@ -845,17 +844,6 @@ sign in chained assignment." (match-beginning 2)) ; limit the search until the assignment nil (1 font-lock-variable-name-face))) - ;; single assignment with type hints, e.g. - ;; a: int = 5 - ;; b: Tuple[Optional[int], Union[Sequence[str], str]] = (None, 'foo') - ;; c: Collection = {1, 2, 3} - ;; d: Mapping[int, str] = {1: 'bar', 2: 'baz'} - (,(python-font-lock-assignment-matcher - (python-rx grouped-assignment-target (* space) - (? ?: (* space) (+ not-simple-operator) (* space)) - (group assignment-operator))) - (1 font-lock-variable-name-face) - (2 'font-lock-operator-face)) ;; special cases ;; (a) = 5 ;; [a] = 5, commit 06541762d7d994bedf0c0bd20601047d43de25d5 Author: Eli Zaretskii Date: Sun May 26 10:28:35 2024 +0300 ; Fix Calc manual * doc/misc/calc.texi (History and Acknowledgments) (Musical Notes): Fix markup due to makeinfo 4.13 support. diff --git a/doc/misc/calc.texi b/doc/misc/calc.texi index bcedee8a946..56ebc589960 100644 --- a/doc/misc/calc.texi +++ b/doc/misc/calc.texi @@ -1197,7 +1197,7 @@ bent, contributed ideas and algorithms for a number of Calc features including modulo forms, primality testing, and float-to-fraction conversion. Units were added at the eager insistence of Mass Sivilotti. Later, -Ulrich Müller at CERN and Przemek Klosowski at NIST provided invaluable +Ulrich M@"{u}ller at CERN and Przemek Klosowski at NIST provided invaluable expert assistance with the units table. As far as I can remember, the idea of using algebraic formulas and variables to represent units dates back to an ancient article in Byte magazine about muMath, an early @@ -28492,12 +28492,25 @@ B and the octave numbered 0 was chosen to correspond to the lowest audible frequency. Using this system, middle C (about 261.625 Hz) corresponds to the note @slanted{C} in octave 4 and is denoted -@slanted{C4}. Any frequency can be described by giving a note plus an +@iftex +@slanted{C@sub{4}}. +@end iftex +@ifnottex +@slanted{C} with subscript @slanted{4}. +@end ifnottex +Any frequency can be described by giving a note plus an offset in cents (where a cent is a ratio of frequencies so that a semitone consists of 100 cents). The midi note number system assigns numbers to notes so that -@slanted{C-1} corresponds to the midi note number 0 and @slanted{G9} +@iftex +@slanted{C@sub{-1}} corresponds to the midi note number 0, and +@slanted{G@sub{9}} +@end iftex +@ifnottex +@slanted{C} with subscript @slanted{-1} corresponds to the midi note +number 0, and @slanted{G} with subscript @slanted{9} +@end ifnottex corresponds to the midi note number 127. A midi controller can have up to 128 keys and each midi note number from 0 to 127 corresponds to a possible key.