mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2026-09-10 07:46:51 -04:00
Update Android port
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): New function requestSelectionUpdate. * java/org/gnu/emacs/EmacsView.java (onCreateInputConnection): Call it instead of losing if getting the current selection fails. * src/android-asset.h (AAsset_seek): Define stub. * src/android.c (android_open): Take mode_t. (android_open_asset, android_close_asset, android_asset_read_quit) (android_asset_read, android_asset_lseek, android_asset_fstat): New functions. * src/android.h (struct android_fd_or_asset): Update prototypes. * src/androidgui.h (enum android_ime_operation): Add new operation to update the selection position. * src/androidterm.c (android_handle_ime_event): Handle new operation. (requestSelectionUpdate): New function. * src/fileio.c (close_file_unwind_emacs_fd): New function. (Fcopy_file, union read_non_regular, read_non_regular) (Finsert_file_contents): Use optimized codepath to insert Android asset files. * src/frame.h (enum text_conversion_operation): New operation. * src/textconv.c (really_request_point_update) (handle_pending_conversion_events_1, request_point_update): New functions. * src/textconv.h: Update prototypes.
This commit is contained in:
parent
31883b8de1
commit
c0a6f14f4a
|
|
@ -203,6 +203,7 @@ public static native void performEditorAction (short window,
|
|||
public static native ExtractedText getExtractedText (short window,
|
||||
ExtractedTextRequest req,
|
||||
int flags);
|
||||
public static native void requestSelectionUpdate (short window);
|
||||
|
||||
|
||||
/* Return the current value of the selection, or -1 upon
|
||||
|
|
|
|||
|
|
@ -573,18 +573,33 @@ else if (child.getVisibility () != GONE)
|
|||
/* Set a reasonable inputType. */
|
||||
info.inputType = InputType.TYPE_CLASS_TEXT;
|
||||
|
||||
/* If this fails or ANDROID_IC_MODE_NULL was requested, then don't
|
||||
initialize the input connection. */
|
||||
|
||||
if (mode == EmacsService.IC_MODE_NULL)
|
||||
{
|
||||
info.inputType = InputType.TYPE_NULL;
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Obtain the current position of point and set it as the
|
||||
selection. */
|
||||
selection = EmacsNative.getSelection (window.handle);
|
||||
|
||||
Log.d (TAG, "onCreateInputConnection: current selection is: " + selection);
|
||||
|
||||
/* If this fails or ANDROID_IC_MODE_NULL was requested, then don't
|
||||
initialize the input connection. */
|
||||
if (mode == EmacsService.IC_MODE_NULL || selection == null)
|
||||
if (selection != null)
|
||||
Log.d (TAG, "onCreateInputConnection: current selection is: "
|
||||
+ selection[0] + ", by " + selection[1]);
|
||||
else
|
||||
{
|
||||
info.inputType = InputType.TYPE_NULL;
|
||||
return null;
|
||||
Log.d (TAG, "onCreateInputConnection: current selection could"
|
||||
+ " not be retrieved.");
|
||||
|
||||
/* If the selection could not be obtained, return 0 by 0.
|
||||
However, ask for the selection position to be updated as
|
||||
soon as possible. */
|
||||
|
||||
selection = new int[] { 0, 0, };
|
||||
EmacsNative.requestSelectionUpdate (window.handle);
|
||||
}
|
||||
|
||||
if (mode == EmacsService.IC_MODE_ACTION)
|
||||
|
|
|
|||
|
|
@ -412,3 +412,11 @@ AAsset_read (AAsset *asset, void *buffer, size_t size)
|
|||
return android_asset_read_internal (asset, MIN (size, INT_MAX),
|
||||
buffer);
|
||||
}
|
||||
|
||||
static off_t
|
||||
AAsset_seek (AAsset *asset, off_t offset, int whence)
|
||||
{
|
||||
/* Java InputStreams don't support seeking at all. */
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
150
src/android.c
150
src/android.c
|
|
@ -1568,7 +1568,7 @@ android_close_on_exec (int fd)
|
|||
contain all assets in the application package. */
|
||||
|
||||
int
|
||||
android_open (const char *filename, int oflag, int mode)
|
||||
android_open (const char *filename, int oflag, mode_t mode)
|
||||
{
|
||||
const char *name;
|
||||
AAsset *asset;
|
||||
|
|
@ -5971,6 +5971,154 @@ android_set_fullscreen (android_window window, bool fullscreen)
|
|||
|
||||
|
||||
|
||||
/* External asset management interface. By using functions here
|
||||
to read and write from files, Emacs can avoid opening a
|
||||
shared memory file descriptor for each ``asset'' file. */
|
||||
|
||||
/* Like android_open. However, return a structure that can
|
||||
either directly hold an AAsset or a file descriptor.
|
||||
|
||||
Value is the structure upon success. Upon failure, value
|
||||
consists of an uninitialized file descriptor, but its asset
|
||||
field is set to -1, and errno is set accordingly. */
|
||||
|
||||
struct android_fd_or_asset
|
||||
android_open_asset (const char *filename, int oflag, mode_t mode)
|
||||
{
|
||||
const char *name;
|
||||
struct android_fd_or_asset fd;
|
||||
AAsset *asset;
|
||||
|
||||
/* Initialize FD by setting its asset to an invalid
|
||||
pointer. */
|
||||
fd.asset = (void *) -1;
|
||||
|
||||
/* See if this is an asset. */
|
||||
|
||||
if (asset_manager && (name = android_get_asset_name (filename)))
|
||||
{
|
||||
/* Return failure for unsupported flags. */
|
||||
|
||||
if (oflag & O_WRONLY || oflag & O_RDWR)
|
||||
{
|
||||
errno = EROFS;
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (oflag & O_DIRECTORY)
|
||||
{
|
||||
errno = ENOTSUP;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Now try to open the asset. */
|
||||
asset = AAssetManager_open (asset_manager, name,
|
||||
AASSET_MODE_STREAMING);
|
||||
|
||||
if (!asset)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Return the asset. */
|
||||
fd.asset = asset;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* If the file is not an asset, fall back to android_open and
|
||||
get a regular file descriptor. */
|
||||
|
||||
fd.fd = android_open (filename, oflag, mode);
|
||||
if (fd.fd < 1)
|
||||
return fd;
|
||||
|
||||
/* Set fd.asset to NULL, signifying that it is a file
|
||||
descriptor. */
|
||||
fd.asset = NULL;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Like android_close. However, it takes a ``file descriptor''
|
||||
opened using android_open_asset. */
|
||||
|
||||
int
|
||||
android_close_asset (struct android_fd_or_asset asset)
|
||||
{
|
||||
if (!asset.asset)
|
||||
return android_close (asset.fd);
|
||||
|
||||
AAsset_close (asset.asset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Like `emacs_read_quit'. However, it handles file descriptors
|
||||
opened using `android_open_asset' as well. */
|
||||
|
||||
ssize_t
|
||||
android_asset_read_quit (struct android_fd_or_asset asset,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (!asset.asset)
|
||||
return emacs_read_quit (asset.fd, buffer, size);
|
||||
|
||||
/* It doesn't seem possible to quit from inside AAsset_read,
|
||||
sadly. */
|
||||
return AAsset_read (asset.asset, buffer, size);
|
||||
}
|
||||
|
||||
/* Like `read'. However, it handles file descriptors opened
|
||||
using `android_open_asset' as well. */
|
||||
|
||||
ssize_t
|
||||
android_asset_read (struct android_fd_or_asset asset,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (!asset.asset)
|
||||
return read (asset.fd, buffer, size);
|
||||
|
||||
/* It doesn't seem possible to quit from inside AAsset_read,
|
||||
sadly. */
|
||||
return AAsset_read (asset.asset, buffer, size);
|
||||
}
|
||||
|
||||
/* Like `lseek', but it handles ``file descriptors'' opened with
|
||||
android_open_asset. */
|
||||
|
||||
off_t
|
||||
android_asset_lseek (struct android_fd_or_asset asset, off_t off,
|
||||
int whence)
|
||||
{
|
||||
if (!asset.asset)
|
||||
return lseek (asset.fd, off, whence);
|
||||
|
||||
return AAsset_seek (asset.asset, off, whence);
|
||||
}
|
||||
|
||||
/* Like `fstat'. */
|
||||
|
||||
int
|
||||
android_asset_fstat (struct android_fd_or_asset asset,
|
||||
struct stat *statb)
|
||||
{
|
||||
if (!asset.asset)
|
||||
return fstat (asset.fd, statb);
|
||||
|
||||
/* Clear statb. */
|
||||
memset (statb, 0, sizeof *statb);
|
||||
|
||||
/* Set the mode. */
|
||||
statb->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
/* Owned by root. */
|
||||
statb->st_uid = 0;
|
||||
statb->st_gid = 0;
|
||||
|
||||
/* Size of the file. */
|
||||
statb->st_size = AAsset_getLength (asset.asset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* ANDROID_STUBIFY */
|
||||
|
||||
/* X emulation functions for Android. */
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ extern int android_emacs_init (int, char **, char *);
|
|||
extern int android_select (int, fd_set *, fd_set *, fd_set *,
|
||||
struct timespec *);
|
||||
|
||||
extern int android_open (const char *, int, int);
|
||||
extern int android_open (const char *, int, mode_t);
|
||||
extern char *android_user_full_name (struct passwd *);
|
||||
extern int android_fstat (int, struct stat *);
|
||||
extern int android_fstatat (int, const char *restrict,
|
||||
|
|
@ -107,6 +107,30 @@ extern void android_closedir (struct android_dir *);
|
|||
|
||||
|
||||
|
||||
/* External asset manager interface. */
|
||||
|
||||
struct android_fd_or_asset
|
||||
{
|
||||
/* The file descriptor. */
|
||||
int fd;
|
||||
|
||||
/* The asset. If set, FD is not a real file descriptor. */
|
||||
void *asset;
|
||||
};
|
||||
|
||||
extern struct android_fd_or_asset android_open_asset (const char *,
|
||||
int, mode_t);
|
||||
extern int android_close_asset (struct android_fd_or_asset);
|
||||
extern ssize_t android_asset_read_quit (struct android_fd_or_asset,
|
||||
void *, size_t);
|
||||
extern ssize_t android_asset_read (struct android_fd_or_asset,
|
||||
void *, size_t);
|
||||
extern off_t android_asset_lseek (struct android_fd_or_asset, off_t, int);
|
||||
extern int android_asset_fstat (struct android_fd_or_asset,
|
||||
struct stat *);
|
||||
|
||||
|
||||
|
||||
/* Very miscellaneous functions. */
|
||||
|
||||
struct android_battery_state
|
||||
|
|
|
|||
|
|
@ -430,6 +430,7 @@ enum android_ime_operation
|
|||
ANDROID_IME_SET_POINT,
|
||||
ANDROID_IME_START_BATCH_EDIT,
|
||||
ANDROID_IME_END_BATCH_EDIT,
|
||||
ANDROID_IME_REQUEST_SELECTION_UPDATE,
|
||||
};
|
||||
|
||||
struct android_ime_event
|
||||
|
|
|
|||
|
|
@ -630,6 +630,10 @@ android_handle_ime_event (union android_event *event, struct frame *f)
|
|||
case ANDROID_IME_END_BATCH_EDIT:
|
||||
end_batch_edit (f, event->ime.counter);
|
||||
break;
|
||||
|
||||
case ANDROID_IME_REQUEST_SELECTION_UPDATE:
|
||||
request_point_update (f, event->ime.counter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5169,6 +5173,28 @@ NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object,
|
|||
return string;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
NATIVE_NAME (requestSelectionUpdate) (JNIEnv *env, jobject object,
|
||||
jshort window)
|
||||
{
|
||||
JNI_STACK_ALIGNMENT_PROLOGUE;
|
||||
|
||||
union android_event event;
|
||||
|
||||
event.ime.type = ANDROID_INPUT_METHOD;
|
||||
event.ime.serial = ++event_serial;
|
||||
event.ime.window = window;
|
||||
event.ime.operation = ANDROID_IME_REQUEST_SELECTION_UPDATE;
|
||||
event.ime.start = 0;
|
||||
event.ime.end = 0;
|
||||
event.ime.length = 0;
|
||||
event.ime.position = 0;
|
||||
event.ime.text = NULL;
|
||||
event.ime.counter = ++edit_counter;
|
||||
|
||||
android_write_event (&event);
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
|
|
|
|||
174
src/fileio.c
174
src/fileio.c
|
|
@ -113,6 +113,37 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
|
||||
#include "commands.h"
|
||||
|
||||
#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
|
||||
|
||||
/* Type describing a file descriptor used by functions such as
|
||||
`insert-file-contents'. */
|
||||
|
||||
typedef int emacs_fd;
|
||||
|
||||
/* Function used to read and open from such a file descriptor. */
|
||||
|
||||
#define emacs_fd_open emacs_open
|
||||
#define emacs_fd_close emacs_close
|
||||
#define emacs_fd_read emacs_read_quit
|
||||
#define emacs_fd_lseek lseek
|
||||
#define emacs_fd_fstat sys_fstat
|
||||
#define emacs_fd_valid_p(fd) ((fd) >= 0)
|
||||
#define emacs_fd_to_int(fds) (fds)
|
||||
|
||||
#else /* HAVE_ANDROID && !defined ANDROID_STUBIFY */
|
||||
|
||||
typedef struct android_fd_or_asset emacs_fd;
|
||||
|
||||
#define emacs_fd_open android_open_asset
|
||||
#define emacs_fd_close android_close_asset
|
||||
#define emacs_fd_read android_asset_read_quit
|
||||
#define emacs_fd_lseek android_asset_lseek
|
||||
#define emacs_fd_fstat android_asset_fstat
|
||||
#define emacs_fd_valid_p(fd) ((fd).asset != ((void *) -1))
|
||||
#define emacs_fd_to_int(fds) ((fds).asset ? -1 : (fds).fd)
|
||||
|
||||
#endif /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
|
||||
|
||||
/* True during writing of auto-save files. */
|
||||
static bool auto_saving;
|
||||
|
||||
|
|
@ -299,6 +330,15 @@ close_file_unwind (int fd)
|
|||
emacs_close (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
close_file_unwind_emacs_fd (void *ptr)
|
||||
{
|
||||
emacs_fd *fd;
|
||||
|
||||
fd = ptr;
|
||||
emacs_fd_close (*fd);
|
||||
}
|
||||
|
||||
void
|
||||
fclose_unwind (void *arg)
|
||||
{
|
||||
|
|
@ -2221,7 +2261,8 @@ permissions. */)
|
|||
#else
|
||||
bool already_exists = false;
|
||||
mode_t new_mask;
|
||||
int ifd, ofd;
|
||||
emacs_fd ifd;
|
||||
int ofd;
|
||||
struct stat st;
|
||||
#endif
|
||||
|
||||
|
|
@ -2265,22 +2306,24 @@ permissions. */)
|
|||
report_file_error ("Copying permissions to", newname);
|
||||
}
|
||||
#else /* not WINDOWSNT */
|
||||
ifd = emacs_open (SSDATA (encoded_file), O_RDONLY | O_NONBLOCK, 0);
|
||||
ifd = emacs_fd_open (SSDATA (encoded_file), O_RDONLY | O_NONBLOCK, 0);
|
||||
|
||||
if (ifd < 0)
|
||||
if (!emacs_fd_valid_p (ifd))
|
||||
report_file_error ("Opening input file", file);
|
||||
|
||||
record_unwind_protect_int (close_file_unwind, ifd);
|
||||
record_unwind_protect_ptr (close_file_unwind_emacs_fd, &ifd);
|
||||
|
||||
if (sys_fstat (ifd, &st) != 0)
|
||||
if (emacs_fd_fstat (ifd, &st) != 0)
|
||||
report_file_error ("Input file status", file);
|
||||
|
||||
if (!NILP (preserve_permissions))
|
||||
{
|
||||
#if HAVE_LIBSELINUX
|
||||
if (is_selinux_enabled ())
|
||||
if (is_selinux_enabled ()
|
||||
&& emacs_fd_to_int (ifd) != -1)
|
||||
{
|
||||
conlength = fgetfilecon (ifd, &con);
|
||||
conlength = fgetfilecon (emacs_fd_to_int (ifd),
|
||||
&con);
|
||||
if (conlength == -1)
|
||||
report_file_error ("Doing fgetfilecon", file);
|
||||
}
|
||||
|
|
@ -2329,7 +2372,8 @@ permissions. */)
|
|||
|
||||
maybe_quit ();
|
||||
|
||||
if (clone_file (ofd, ifd))
|
||||
if (emacs_fd_to_int (ifd) != -1
|
||||
&& clone_file (ofd, emacs_fd_to_int (ifd)))
|
||||
newsize = st.st_size;
|
||||
else
|
||||
{
|
||||
|
|
@ -2337,30 +2381,38 @@ permissions. */)
|
|||
ssize_t copied;
|
||||
|
||||
#ifndef MSDOS
|
||||
for (newsize = 0; newsize < insize; newsize += copied)
|
||||
newsize = 0;
|
||||
|
||||
if (emacs_fd_to_int (ifd) != -1)
|
||||
{
|
||||
/* Copy at most COPY_MAX bytes at a time; this is min
|
||||
(PTRDIFF_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t ssize_max = TYPE_MAXIMUM (ssize_t);
|
||||
ptrdiff_t copy_max = min (ssize_max, SIZE_MAX) >> 30 << 30;
|
||||
off_t intail = insize - newsize;
|
||||
ptrdiff_t len = min (intail, copy_max);
|
||||
copied = copy_file_range (ifd, NULL, ofd, NULL, len, 0);
|
||||
if (copied <= 0)
|
||||
break;
|
||||
maybe_quit ();
|
||||
for (; newsize < insize; newsize += copied)
|
||||
{
|
||||
/* Copy at most COPY_MAX bytes at a time; this is min
|
||||
(PTRDIFF_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t ssize_max = TYPE_MAXIMUM (ssize_t);
|
||||
ptrdiff_t copy_max = min (ssize_max, SIZE_MAX) >> 30 << 30;
|
||||
off_t intail = insize - newsize;
|
||||
ptrdiff_t len = min (intail, copy_max);
|
||||
copied = copy_file_range (emacs_fd_to_int (ifd), NULL,
|
||||
ofd, NULL, len, 0);
|
||||
if (copied <= 0)
|
||||
break;
|
||||
maybe_quit ();
|
||||
}
|
||||
}
|
||||
#endif /* MSDOS */
|
||||
|
||||
/* Fall back on read+write if copy_file_range failed, or if the
|
||||
input is empty and so could be a /proc file. read+write will
|
||||
either succeed, or report an error more precisely than
|
||||
copy_file_range would. */
|
||||
input is empty and so could be a /proc file, or if ifd is an
|
||||
invention of android.c. read+write will either succeed, or
|
||||
report an error more precisely than copy_file_range
|
||||
would. */
|
||||
if (newsize != insize || insize == 0)
|
||||
{
|
||||
char buf[MAX_ALLOCA];
|
||||
for (; (copied = emacs_read_quit (ifd, buf, sizeof buf));
|
||||
|
||||
for (; (copied = emacs_fd_read (ifd, buf, sizeof buf));
|
||||
newsize += copied)
|
||||
{
|
||||
if (copied < 0)
|
||||
|
|
@ -2408,8 +2460,10 @@ permissions. */)
|
|||
}
|
||||
}
|
||||
|
||||
switch (!NILP (preserve_permissions)
|
||||
? qcopy_acl (SSDATA (encoded_file), ifd,
|
||||
switch ((!NILP (preserve_permissions)
|
||||
&& emacs_fd_to_int (ifd) != -1)
|
||||
? qcopy_acl (SSDATA (encoded_file),
|
||||
emacs_fd_to_int (ifd),
|
||||
SSDATA (encoded_newname), ofd,
|
||||
preserved_permissions)
|
||||
: (already_exists
|
||||
|
|
@ -2449,7 +2503,9 @@ permissions. */)
|
|||
if (emacs_close (ofd) < 0)
|
||||
report_file_error ("Write error", newname);
|
||||
|
||||
emacs_close (ifd);
|
||||
/* Note that ifd is not closed twice because unwind_protects are
|
||||
discarded at the end of this function. */
|
||||
emacs_fd_close (ifd);
|
||||
|
||||
#ifdef MSDOS
|
||||
/* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
|
||||
|
|
@ -3826,7 +3882,7 @@ union read_non_regular
|
|||
{
|
||||
struct
|
||||
{
|
||||
int fd;
|
||||
emacs_fd fd;
|
||||
ptrdiff_t inserted, trytry;
|
||||
} s;
|
||||
GCALIGNED_UNION_MEMBER
|
||||
|
|
@ -3837,10 +3893,10 @@ static Lisp_Object
|
|||
read_non_regular (Lisp_Object state)
|
||||
{
|
||||
union read_non_regular *data = XFIXNUMPTR (state);
|
||||
int nbytes = emacs_read_quit (data->s.fd,
|
||||
((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
|
||||
+ data->s.inserted),
|
||||
data->s.trytry);
|
||||
int nbytes = emacs_fd_read (data->s.fd,
|
||||
((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
|
||||
+ data->s.inserted),
|
||||
data->s.trytry);
|
||||
return make_fixnum (nbytes);
|
||||
}
|
||||
|
||||
|
|
@ -3989,7 +4045,7 @@ by calling `format-decode', which see. */)
|
|||
{
|
||||
struct stat st;
|
||||
struct timespec mtime;
|
||||
int fd;
|
||||
emacs_fd fd;
|
||||
ptrdiff_t inserted = 0;
|
||||
int unprocessed;
|
||||
specpdl_ref count = SPECPDL_INDEX ();
|
||||
|
|
@ -4067,8 +4123,8 @@ by calling `format-decode', which see. */)
|
|||
orig_filename = filename;
|
||||
filename = ENCODE_FILE (filename);
|
||||
|
||||
fd = emacs_open (SSDATA (filename), O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
fd = emacs_fd_open (SSDATA (filename), O_RDONLY, 0);
|
||||
if (!emacs_fd_valid_p (fd))
|
||||
{
|
||||
save_errno = errno;
|
||||
if (NILP (visit))
|
||||
|
|
@ -4086,7 +4142,7 @@ by calling `format-decode', which see. */)
|
|||
}
|
||||
|
||||
specpdl_ref fd_index = SPECPDL_INDEX ();
|
||||
record_unwind_protect_int (close_file_unwind, fd);
|
||||
record_unwind_protect_ptr (close_file_unwind_emacs_fd, &fd);
|
||||
|
||||
/* Replacement should preserve point as it preserves markers. */
|
||||
if (!NILP (replace))
|
||||
|
|
@ -4096,7 +4152,7 @@ by calling `format-decode', which see. */)
|
|||
XCAR (XCAR (window_markers)));
|
||||
}
|
||||
|
||||
if (sys_fstat (fd, &st) != 0)
|
||||
if (emacs_fd_fstat (fd, &st) != 0)
|
||||
report_file_error ("Input file status", orig_filename);
|
||||
mtime = get_stat_mtime (&st);
|
||||
|
||||
|
|
@ -4117,7 +4173,7 @@ by calling `format-decode', which see. */)
|
|||
xsignal2 (Qfile_error,
|
||||
build_string ("not a regular file"), orig_filename);
|
||||
|
||||
seekable = lseek (fd, 0, SEEK_CUR) < 0;
|
||||
seekable = emacs_fd_lseek (fd, 0, SEEK_CUR) < 0;
|
||||
if (!NILP (beg) && !seekable)
|
||||
xsignal2 (Qfile_error,
|
||||
build_string ("cannot use a start position in a non-seekable file/device"),
|
||||
|
|
@ -4196,17 +4252,17 @@ by calling `format-decode', which see. */)
|
|||
int nread;
|
||||
|
||||
if (st.st_size <= (1024 * 4))
|
||||
nread = emacs_read_quit (fd, read_buf, 1024 * 4);
|
||||
nread = emacs_fd_read (fd, read_buf, 1024 * 4);
|
||||
else
|
||||
{
|
||||
nread = emacs_read_quit (fd, read_buf, 1024);
|
||||
nread = emacs_fd_read (fd, read_buf, 1024);
|
||||
if (nread == 1024)
|
||||
{
|
||||
int ntail;
|
||||
if (lseek (fd, st.st_size - 1024 * 3, SEEK_CUR) < 0)
|
||||
if (emacs_fd_lseek (fd, st.st_size - 1024 * 3, SEEK_CUR) < 0)
|
||||
report_file_error ("Setting file position",
|
||||
orig_filename);
|
||||
ntail = emacs_read_quit (fd, read_buf + nread, 1024 * 3);
|
||||
ntail = emacs_fd_read (fd, read_buf + nread, 1024 * 3);
|
||||
nread = ntail < 0 ? ntail : nread + ntail;
|
||||
}
|
||||
}
|
||||
|
|
@ -4247,7 +4303,7 @@ by calling `format-decode', which see. */)
|
|||
specpdl_ptr--;
|
||||
|
||||
/* Rewind the file for the actual read done later. */
|
||||
if (lseek (fd, 0, SEEK_SET) < 0)
|
||||
if (emacs_fd_lseek (fd, 0, SEEK_SET) < 0)
|
||||
report_file_error ("Setting file position", orig_filename);
|
||||
}
|
||||
}
|
||||
|
|
@ -4306,7 +4362,7 @@ by calling `format-decode', which see. */)
|
|||
|
||||
if (beg_offset != 0)
|
||||
{
|
||||
if (lseek (fd, beg_offset, SEEK_SET) < 0)
|
||||
if (emacs_fd_lseek (fd, beg_offset, SEEK_SET) < 0)
|
||||
report_file_error ("Setting file position", orig_filename);
|
||||
}
|
||||
|
||||
|
|
@ -4314,7 +4370,7 @@ by calling `format-decode', which see. */)
|
|||
match the text at the beginning of the buffer. */
|
||||
while (true)
|
||||
{
|
||||
int nread = emacs_read_quit (fd, read_buf, sizeof read_buf);
|
||||
int nread = emacs_fd_read (fd, read_buf, sizeof read_buf);
|
||||
if (nread < 0)
|
||||
report_file_error ("Read error", orig_filename);
|
||||
else if (nread == 0)
|
||||
|
|
@ -4349,7 +4405,7 @@ by calling `format-decode', which see. */)
|
|||
there's no need to replace anything. */
|
||||
if (same_at_start - BEGV_BYTE == end_offset - beg_offset)
|
||||
{
|
||||
emacs_close (fd);
|
||||
emacs_fd_close (fd);
|
||||
clear_unwind_protect (fd_index);
|
||||
|
||||
/* Truncate the buffer to the size of the file. */
|
||||
|
|
@ -4372,14 +4428,14 @@ by calling `format-decode', which see. */)
|
|||
break;
|
||||
/* How much can we scan in the next step? */
|
||||
trial = min (curpos, sizeof read_buf);
|
||||
if (lseek (fd, curpos - trial, SEEK_SET) < 0)
|
||||
if (emacs_fd_lseek (fd, curpos - trial, SEEK_SET) < 0)
|
||||
report_file_error ("Setting file position", orig_filename);
|
||||
|
||||
total_read = nread = 0;
|
||||
while (total_read < trial)
|
||||
{
|
||||
nread = emacs_read_quit (fd, read_buf + total_read,
|
||||
trial - total_read);
|
||||
nread = emacs_fd_read (fd, read_buf + total_read,
|
||||
trial - total_read);
|
||||
if (nread < 0)
|
||||
report_file_error ("Read error", orig_filename);
|
||||
else if (nread == 0)
|
||||
|
|
@ -4499,7 +4555,7 @@ by calling `format-decode', which see. */)
|
|||
/* First read the whole file, performing code conversion into
|
||||
CONVERSION_BUFFER. */
|
||||
|
||||
if (lseek (fd, beg_offset, SEEK_SET) < 0)
|
||||
if (emacs_fd_lseek (fd, beg_offset, SEEK_SET) < 0)
|
||||
report_file_error ("Setting file position", orig_filename);
|
||||
|
||||
inserted = 0; /* Bytes put into CONVERSION_BUFFER so far. */
|
||||
|
|
@ -4510,8 +4566,8 @@ by calling `format-decode', which see. */)
|
|||
/* Read at most READ_BUF_SIZE bytes at a time, to allow
|
||||
quitting while reading a huge file. */
|
||||
|
||||
this = emacs_read_quit (fd, read_buf + unprocessed,
|
||||
READ_BUF_SIZE - unprocessed);
|
||||
this = emacs_fd_read (fd, read_buf + unprocessed,
|
||||
READ_BUF_SIZE - unprocessed);
|
||||
if (this <= 0)
|
||||
break;
|
||||
|
||||
|
|
@ -4526,7 +4582,7 @@ by calling `format-decode', which see. */)
|
|||
|
||||
if (this < 0)
|
||||
report_file_error ("Read error", orig_filename);
|
||||
emacs_close (fd);
|
||||
emacs_fd_close (fd);
|
||||
clear_unwind_protect (fd_index);
|
||||
|
||||
if (unprocessed > 0)
|
||||
|
|
@ -4673,7 +4729,7 @@ by calling `format-decode', which see. */)
|
|||
|
||||
if (beg_offset != 0 || !NILP (replace))
|
||||
{
|
||||
if (lseek (fd, beg_offset, SEEK_SET) < 0)
|
||||
if (emacs_fd_lseek (fd, beg_offset, SEEK_SET) < 0)
|
||||
report_file_error ("Setting file position", orig_filename);
|
||||
}
|
||||
|
||||
|
|
@ -4726,10 +4782,10 @@ by calling `format-decode', which see. */)
|
|||
/* Allow quitting out of the actual I/O. We don't make text
|
||||
part of the buffer until all the reading is done, so a C-g
|
||||
here doesn't do any harm. */
|
||||
this = emacs_read_quit (fd,
|
||||
((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
|
||||
+ inserted),
|
||||
trytry);
|
||||
this = emacs_fd_read (fd,
|
||||
((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
|
||||
+ inserted),
|
||||
trytry);
|
||||
}
|
||||
|
||||
if (this <= 0)
|
||||
|
|
@ -4756,7 +4812,7 @@ by calling `format-decode', which see. */)
|
|||
else
|
||||
Fset (Qdeactivate_mark, Qt);
|
||||
|
||||
emacs_close (fd);
|
||||
emacs_fd_close (fd);
|
||||
clear_unwind_protect (fd_index);
|
||||
|
||||
if (read_quit < 0)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ enum text_conversion_operation
|
|||
TEXTCONV_SET_COMPOSING_REGION,
|
||||
TEXTCONV_SET_POINT_AND_MARK,
|
||||
TEXTCONV_DELETE_SURROUNDING_TEXT,
|
||||
TEXTCONV_REQUEST_POINT_UPDATE,
|
||||
};
|
||||
|
||||
/* Structure describing a single edit being performed by the input
|
||||
|
|
|
|||
|
|
@ -957,6 +957,26 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
|
|||
unbind_to (count, Qnil);
|
||||
}
|
||||
|
||||
/* Update the interface with F's new point and mark. If a batch edit
|
||||
is in progress, schedule the update for when it finishes
|
||||
instead. */
|
||||
|
||||
static void
|
||||
really_request_point_update (struct frame *f)
|
||||
{
|
||||
/* If F's old selected window is no longer live, fail. */
|
||||
|
||||
if (!WINDOW_LIVE_P (f->old_selected_window))
|
||||
return;
|
||||
|
||||
if (f->conversion.batch_edit_count > 0)
|
||||
f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
|
||||
else if (text_interface && text_interface->point_changed)
|
||||
text_interface->point_changed (f,
|
||||
XWINDOW (f->old_selected_window),
|
||||
current_buffer);
|
||||
}
|
||||
|
||||
/* Set point in F to POSITION. If MARK is not POSITION, activate the
|
||||
mark and set MARK to that as well.
|
||||
|
||||
|
|
@ -1163,6 +1183,10 @@ handle_pending_conversion_events_1 (struct frame *f,
|
|||
really_delete_surrounding_text (f, XFIXNUM (XCAR (data)),
|
||||
XFIXNUM (XCDR (data)));
|
||||
break;
|
||||
|
||||
case TEXTCONV_REQUEST_POINT_UPDATE:
|
||||
really_request_point_update (f);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Signal success. */
|
||||
|
|
@ -1457,6 +1481,25 @@ delete_surrounding_text (struct frame *f, ptrdiff_t left,
|
|||
input_pending = true;
|
||||
}
|
||||
|
||||
/* Request an immediate call to INTERFACE->point_changed with the new
|
||||
details of F's region unless a batch edit is in progress. */
|
||||
|
||||
void
|
||||
request_point_update (struct frame *f, unsigned long counter)
|
||||
{
|
||||
struct text_conversion_action *action, **last;
|
||||
|
||||
action = xmalloc (sizeof *action);
|
||||
action->operation = TEXTCONV_REQUEST_POINT_UPDATE;
|
||||
action->data = Qnil;
|
||||
action->next = NULL;
|
||||
action->counter = counter;
|
||||
for (last = &f->conversion.actions; *last; last = &(*last)->next)
|
||||
;;
|
||||
*last = action;
|
||||
input_pending = true;
|
||||
}
|
||||
|
||||
/* Return N characters of text around point in F's old selected
|
||||
window.
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ extern void textconv_set_point_and_mark (struct frame *, ptrdiff_t,
|
|||
ptrdiff_t, unsigned long);
|
||||
extern void delete_surrounding_text (struct frame *, ptrdiff_t,
|
||||
ptrdiff_t, unsigned long);
|
||||
extern void request_point_update (struct frame *, unsigned long);
|
||||
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
|
||||
ptrdiff_t *, ptrdiff_t *, ptrdiff_t *);
|
||||
extern bool conversion_disabled_p (void);
|
||||
|
|
|
|||
Loading…
Reference in a new issue