mirror of https://github.com/adamdruppe/arsd.git
fixes
This commit is contained in:
parent
0a3995a14d
commit
0367ac70e7
41
cgi.d
41
cgi.d
|
@ -3354,10 +3354,15 @@ bool tryAddonServers(string[] args) {
|
||||||
printf("Add-on servers not compiled in.\n");
|
printf("Add-on servers not compiled in.\n");
|
||||||
return true;
|
return true;
|
||||||
case "--timer-server":
|
case "--timer-server":
|
||||||
|
try {
|
||||||
version(with_addon_servers)
|
version(with_addon_servers)
|
||||||
runTimerServer();
|
runTimerServer();
|
||||||
else
|
else
|
||||||
printf("Add-on servers not compiled in.\n");
|
printf("Add-on servers not compiled in.\n");
|
||||||
|
} catch(Throwable t) {
|
||||||
|
import std.file;
|
||||||
|
std.file.write("/tmp/timer-exception", t.toString);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
case "--timed-jobs":
|
case "--timed-jobs":
|
||||||
import core.demangle;
|
import core.demangle;
|
||||||
|
@ -5985,7 +5990,7 @@ void startAddonServer()(string arg) {
|
||||||
import core.sys.posix.unistd;
|
import core.sys.posix.unistd;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
const(char)*[16] args;
|
const(char)*[16] args;
|
||||||
args[0] = "ARSD_CGI_WEBSOCKET_SERVER";
|
args[0] = "ARSD_CGI_ADDON_SERVER";
|
||||||
args[1] = arg.ptr;
|
args[1] = arg.ptr;
|
||||||
posix_spawn(&pid, "/proc/self/exe",
|
posix_spawn(&pid, "/proc/self/exe",
|
||||||
null,
|
null,
|
||||||
|
@ -6459,6 +6464,13 @@ mixin template ImplementRpcClientInterface(T, string serverPath, string cmdArg)
|
||||||
|
|
||||||
version(Posix) {{
|
version(Posix) {{
|
||||||
auto ret = send(connectionHandle, sendable.ptr, sendable.length, 0);
|
auto ret = send(connectionHandle, sendable.ptr, sendable.length, 0);
|
||||||
|
|
||||||
|
if(ret == -1) {
|
||||||
|
throw new Exception("send returned -1, errno: " ~ to!string(errno));
|
||||||
|
} else if(ret == 0) {
|
||||||
|
throw new Exception("Connection to addon server lost");
|
||||||
|
} if(ret < sendable.length)
|
||||||
|
throw new Exception("Send failed to send all");
|
||||||
assert(ret == sendable.length);
|
assert(ret == sendable.length);
|
||||||
}} // FIXME Windows impl
|
}} // FIXME Windows impl
|
||||||
|
|
||||||
|
@ -6514,6 +6526,7 @@ void dispatchRpcServer(Interface, Class)(Class this_, ubyte[] data, int fd) if(i
|
||||||
|
|
||||||
int dataLocation;
|
int dataLocation;
|
||||||
ubyte[] grab(int sz) {
|
ubyte[] grab(int sz) {
|
||||||
|
if(sz == 0) assert(0);
|
||||||
auto d = data[dataLocation .. dataLocation + sz];
|
auto d = data[dataLocation .. dataLocation + sz];
|
||||||
dataLocation += sz;
|
dataLocation += sz;
|
||||||
return d;
|
return d;
|
||||||
|
@ -6547,7 +6560,13 @@ void dispatchRpcServer(Interface, Class)(Class this_, ubyte[] data, int fd) if(i
|
||||||
|
|
||||||
version(Posix) {
|
version(Posix) {
|
||||||
auto r = send(fd, sendable.ptr, sendable.length, 0);
|
auto r = send(fd, sendable.ptr, sendable.length, 0);
|
||||||
assert(r == sendable.length);
|
if(r == -1) {
|
||||||
|
throw new Exception("send returned -1, errno: " ~ to!string(errno));
|
||||||
|
} else if(r == 0) {
|
||||||
|
throw new Exception("Connection to addon client lost");
|
||||||
|
} if(r < sendable.length)
|
||||||
|
throw new Exception("Send failed to send all");
|
||||||
|
|
||||||
} // FIXME Windows impl
|
} // FIXME Windows impl
|
||||||
}
|
}
|
||||||
break sw;
|
break sw;
|
||||||
|
@ -7016,7 +7035,9 @@ final class ScheduledJobServerImplementation : ScheduledJobServer, EventIoServer
|
||||||
if(fd == -1)
|
if(fd == -1)
|
||||||
throw new Exception("fd timer create failed");
|
throw new Exception("fd timer create failed");
|
||||||
|
|
||||||
auto job = Job(executable, func, args, fd, nj);
|
foreach(ref arg; args)
|
||||||
|
arg = arg.idup;
|
||||||
|
auto job = Job(executable.idup, func.idup, .dup(args), fd, nj);
|
||||||
|
|
||||||
itimerspec value;
|
itimerspec value;
|
||||||
value.it_value.tv_sec = when;
|
value.it_value.tv_sec = when;
|
||||||
|
@ -7030,8 +7051,11 @@ final class ScheduledJobServerImplementation : ScheduledJobServer, EventIoServer
|
||||||
|
|
||||||
auto op = allocateIoOp(fd, IoOp.Read, 16, (IoOp* op, int fd) {
|
auto op = allocateIoOp(fd, IoOp.Read, 16, (IoOp* op, int fd) {
|
||||||
jobs.remove(nj);
|
jobs.remove(nj);
|
||||||
|
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, null);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
spawnProcess([job.executable, "--timed-job", job.func] ~ args);
|
|
||||||
|
spawnProcess([job.executable, "--timed-job", job.func] ~ job.args);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -7055,6 +7079,8 @@ final class ScheduledJobServerImplementation : ScheduledJobServer, EventIoServer
|
||||||
if(job is null)
|
if(job is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
jobs.remove(jobId);
|
||||||
|
|
||||||
version(linux) {
|
version(linux) {
|
||||||
import core.sys.linux.timerfd;
|
import core.sys.linux.timerfd;
|
||||||
import core.sys.linux.epoll;
|
import core.sys.linux.epoll;
|
||||||
|
@ -7453,6 +7479,13 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
|
||||||
import core.sys.posix.signal;
|
import core.sys.posix.signal;
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
static extern(C) void sigchldhandler(int) {
|
||||||
|
int status;
|
||||||
|
import w = core.sys.posix.sys.wait;
|
||||||
|
w.wait(&status);
|
||||||
|
}
|
||||||
|
signal(SIGCHLD, &sigchldhandler);
|
||||||
|
|
||||||
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if(sock == -1)
|
if(sock == -1)
|
||||||
throw new Exception("socket " ~ to!string(errno));
|
throw new Exception("socket " ~ to!string(errno));
|
||||||
|
|
3
dub.json
3
dub.json
|
@ -477,7 +477,8 @@
|
||||||
"targetType": "library",
|
"targetType": "library",
|
||||||
"sourceFiles": ["libssh2.d"],
|
"sourceFiles": ["libssh2.d"],
|
||||||
"importPaths": ["."],
|
"importPaths": ["."],
|
||||||
"libs": ["ssh2"],
|
"libs-posix": ["ssh2"],
|
||||||
|
"libs-windows": ["libssh2"],
|
||||||
"dflags": ["-mv=arsd.libssh2=libssh2.d"]
|
"dflags": ["-mv=arsd.libssh2=libssh2.d"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
See [imageResize] for the main function, all others are lower level if you need
|
See [imageResize] for the main function, all others are lower level if you need
|
||||||
more control.
|
more control.
|
||||||
|
|
||||||
|
Note that this focuses more on quality than speed. You can tweak the `filterScale`
|
||||||
|
argument to speed things up at the expense of quality though (lower number = faster).
|
||||||
|
|
||||||
|
|
||||||
Authors:
|
Authors:
|
||||||
Originally written in C by Rich Geldreich, ported to D by ketmar.
|
Originally written in C by Rich Geldreich, ported to D by ketmar.
|
||||||
|
@ -78,6 +81,29 @@ public int imageResizeFindFilter (const(char)[] name, const(char)[] defaultFilte
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/++
|
||||||
|
Calculates a new size that fits inside the maximums while keeping the original aspect ratio.
|
||||||
|
|
||||||
|
History:
|
||||||
|
Added March 18, 2021 (dub v9.4)
|
||||||
|
+/
|
||||||
|
public Size calculateSizeKeepingAspectRatio(int currentWidth, int currentHeight, int maxWidth, int maxHeight) {
|
||||||
|
if(currentWidth <= maxWidth && currentHeight <= maxHeight)
|
||||||
|
return Size(currentWidth, currentHeight);
|
||||||
|
|
||||||
|
float shrinkage = 1.0;
|
||||||
|
|
||||||
|
if(currentWidth > maxWidth) {
|
||||||
|
shrinkage = cast(float) maxWidth / currentWidth;
|
||||||
|
}
|
||||||
|
if(currentHeight > maxHeight) {
|
||||||
|
auto shrinkage2 = cast(float) maxHeight / currentHeight;
|
||||||
|
if(shrinkage2 < shrinkage)
|
||||||
|
shrinkage = shrinkage2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Size(cast(int) (currentWidth * shrinkage), cast(int) (currentHeight * shrinkage));
|
||||||
|
}
|
||||||
|
|
||||||
// ////////////////////////////////////////////////////////////////////////// //
|
// ////////////////////////////////////////////////////////////////////////// //
|
||||||
/// Resize image.
|
/// Resize image.
|
||||||
|
|
104
libssh2.d
104
libssh2.d
|
@ -57,7 +57,7 @@ void main() {
|
||||||
|
|
||||||
char[1024] buffer;
|
char[1024] buffer;
|
||||||
again:
|
again:
|
||||||
auto got = libssh2_sftp_read(handle, buffer.ptr, cast(int) buffer.length);
|
auto got = libssh2_sftp_read(handle, buffer.ptr, buffer.length);
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
writeln(buffer[0 .. got]);
|
writeln(buffer[0 .. got]);
|
||||||
|
@ -266,9 +266,87 @@ extern(C) {
|
||||||
|
|
||||||
ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
|
ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
|
||||||
ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
|
ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
|
||||||
|
|
||||||
|
enum LIBSSH2_SFTP_ATTR {
|
||||||
|
SIZE = 0x00000001,
|
||||||
|
UIDGID = 0x00000002,
|
||||||
|
PERMISSIONS = 0x00000004,
|
||||||
|
ACMODTIME = 0x00000008,
|
||||||
|
EXTENDED = 0x80000000,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LIBSSH2_SFTP_ATTRIBUTES {
|
||||||
|
c_ulong flags; // see LIBSSH2_SFTP_ATTR
|
||||||
|
|
||||||
|
ulong filesize;
|
||||||
|
c_ulong uid, gid;
|
||||||
|
c_ulong permissions;
|
||||||
|
c_ulong atime, mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle,
|
||||||
|
char *buffer, size_t buffer_maxlen,
|
||||||
|
char *longentry, size_t longentry_maxlen, // longentry is just a user-friendly display
|
||||||
|
LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||||
|
int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
uint,
|
||||||
|
int stat_type,
|
||||||
|
LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||||
|
int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle,
|
||||||
|
LIBSSH2_SFTP_STATVFS *st);
|
||||||
|
int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
size_t path_len,
|
||||||
|
LIBSSH2_SFTP_STATVFS *st);
|
||||||
|
int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
uint);
|
||||||
|
int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
uint, c_long mode);
|
||||||
|
int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *filename,
|
||||||
|
uint);
|
||||||
|
int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *path,
|
||||||
|
uint,
|
||||||
|
char *target,
|
||||||
|
uint,
|
||||||
|
int link_type);
|
||||||
|
int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp,
|
||||||
|
const char *source_filename,
|
||||||
|
uint,
|
||||||
|
const char *dest_filename,
|
||||||
|
uint,
|
||||||
|
c_long flags);
|
||||||
|
|
||||||
|
struct LIBSSH2_SFTP_STATVFS {
|
||||||
|
ulong f_bsize; /* file system block size */
|
||||||
|
ulong f_frsize; /* fragment size */
|
||||||
|
ulong f_blocks; /* size of fs in f_frsize units */
|
||||||
|
ulong f_bfree; /* # free blocks */
|
||||||
|
ulong f_bavail; /* # free blocks for non-root */
|
||||||
|
ulong f_files; /* # inodes */
|
||||||
|
ulong f_ffree; /* # free inodes */
|
||||||
|
ulong f_favail; /* # free inodes for non-root */
|
||||||
|
ulong f_fsid; /* file system ID */
|
||||||
|
ulong f_flag; /* mount flags */
|
||||||
|
ulong f_namemax; /* maximum filename length */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* end sftp */
|
/* end sftp */
|
||||||
|
|
||||||
int libssh2_userauth_password(LIBSSH2_SESSION*, const char* username, const char* password);
|
int libssh2_userauth_password_ex(LIBSSH2_SESSION *session,
|
||||||
|
const char *username,
|
||||||
|
uint username_len,
|
||||||
|
const char *password,
|
||||||
|
uint password_len,
|
||||||
|
void* passwd_change_cb);
|
||||||
|
//LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
|
||||||
|
|
||||||
|
//int libssh2_userauth_password(LIBSSH2_SESSION*, const char* username, const char* password);
|
||||||
int libssh2_userauth_publickey_fromfile_ex(
|
int libssh2_userauth_publickey_fromfile_ex(
|
||||||
LIBSSH2_SESSION* session,
|
LIBSSH2_SESSION* session,
|
||||||
const char *username,
|
const char *username,
|
||||||
|
@ -277,6 +355,15 @@ extern(C) {
|
||||||
const char *privatekey,
|
const char *privatekey,
|
||||||
const char *passphrase);
|
const char *passphrase);
|
||||||
|
|
||||||
|
struct LIBSSH2_LISTENER {}
|
||||||
|
LIBSSH2_LISTENER * libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host,
|
||||||
|
int port, int *bound_port,
|
||||||
|
int queue_maxsize);
|
||||||
|
int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
|
||||||
|
LIBSSH2_CHANNEL * libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
|
||||||
|
LIBSSH2_CHANNEL * libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host,
|
||||||
|
int port, const char *shost, int sport);
|
||||||
|
|
||||||
struct LIBSSH2_CHANNEL {}
|
struct LIBSSH2_CHANNEL {}
|
||||||
LIBSSH2_CHANNEL* libssh2_channel_open_ex(
|
LIBSSH2_CHANNEL* libssh2_channel_open_ex(
|
||||||
LIBSSH2_SESSION *session,
|
LIBSSH2_SESSION *session,
|
||||||
|
@ -352,4 +439,17 @@ extern(C) {
|
||||||
enum LIBSSH2_FLAG_SIGPIPE = 1;
|
enum LIBSSH2_FLAG_SIGPIPE = 1;
|
||||||
enum LIBSSH2_FLAG_COMPRESS = 2;
|
enum LIBSSH2_FLAG_COMPRESS = 2;
|
||||||
|
|
||||||
|
|
||||||
|
int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel,
|
||||||
|
int single_connection,
|
||||||
|
const char *auth_proto,
|
||||||
|
const char *auth_cookie,
|
||||||
|
int screen_number);
|
||||||
|
|
||||||
|
|
||||||
|
int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel);
|
||||||
|
int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, char **exitsignal, size_t *exitsignal_len, char **errmsg, size_t *errmsg_len, char **langtag, size_t *langtag_len);
|
||||||
|
|
||||||
|
int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
139
rss.d
139
rss.d
|
@ -23,20 +23,72 @@ struct Feed {
|
||||||
static struct Item {
|
static struct Item {
|
||||||
string title; ///
|
string title; ///
|
||||||
string link; ///
|
string link; ///
|
||||||
string description; ///
|
string description; /// could be html or text!
|
||||||
string author; ///
|
string author; /// Typical format: email (name)
|
||||||
string publicationDate; ///
|
string publicationDate; /// the format is 2005-07-31T12:29:29Z
|
||||||
string lastUpdatedDate; ///
|
string lastUpdatedDate; /// the format is 2005-07-31T12:29:29Z
|
||||||
string guid; ///
|
string guid; ///
|
||||||
|
|
||||||
string enclosureUri; ///
|
string enclosureUri; ///
|
||||||
string enclosureType; ///
|
string enclosureType; /// a mime type
|
||||||
string enclosureSize; ///
|
string enclosureSize; ///
|
||||||
}
|
}
|
||||||
|
|
||||||
Item[] items; ///
|
Item[] items; ///
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/+
|
||||||
|
import arsd.cgi;
|
||||||
|
mixin GenericMain!handler;
|
||||||
|
void handler(Cgi cgi) {
|
||||||
|
cgi.setResponseContentType("application/atom+xml");
|
||||||
|
cgi.write(feedToAtom(parseFeed(Document.fromUrl("http://dpldocs.info/this-week-in-d/twid.rss", true).root)).toString);
|
||||||
|
}
|
||||||
|
+/
|
||||||
|
|
||||||
|
/++
|
||||||
|
Turns a generic feed back into an Atom document.
|
||||||
|
|
||||||
|
History:
|
||||||
|
Added March 18, 2021
|
||||||
|
+/
|
||||||
|
XmlDocument feedToAtom(Feed feed) {
|
||||||
|
auto document = new XmlDocument(`<feed xmlns="http://www.w3.org/2005/Atom"></feed>`);
|
||||||
|
document.root.addChild("title", feed.title);
|
||||||
|
document.root.addChild("subtitle", feed.description);
|
||||||
|
document.root.addChild("updated", feed.lastUpdated);
|
||||||
|
|
||||||
|
foreach(item; feed.items) {
|
||||||
|
auto entry = document.root.addChild("entry");
|
||||||
|
entry.addChild("title", item.title);
|
||||||
|
entry.addChild("link").setAttribute("href", item.link);
|
||||||
|
if(item.enclosureUri.length)
|
||||||
|
entry.addChild("link").
|
||||||
|
setAttribute("rel", "enclosure").
|
||||||
|
setAttribute("href", item.enclosureUri).
|
||||||
|
setAttribute("length", item.enclosureSize).
|
||||||
|
setAttribute("type", item.enclosureType);
|
||||||
|
entry.addChild("id", item.guid);
|
||||||
|
entry.addChild("published", item.publicationDate);
|
||||||
|
entry.addChild("updated", item.lastUpdatedDate);
|
||||||
|
entry.addChild("content", item.description).setAttribute("type", "html"); // or summary? idk
|
||||||
|
if(item.author.length) {
|
||||||
|
auto author = entry.addChild("author");
|
||||||
|
import std.string;
|
||||||
|
auto idx = item.author.indexOf("(");
|
||||||
|
if(idx == -1) {
|
||||||
|
author.addChild("email", item.author);
|
||||||
|
} else {
|
||||||
|
if(item.author.length > idx + 2)
|
||||||
|
author.addChild("name", item.author[idx + 1 .. $-1]);
|
||||||
|
author.addChild("email", item.author[0 .. idx -1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
enum FeedType {
|
enum FeedType {
|
||||||
unknown, ///
|
unknown, ///
|
||||||
|
@ -100,7 +152,7 @@ struct RssChannel {
|
||||||
Feed f;
|
Feed f;
|
||||||
f.title = this.title;
|
f.title = this.title;
|
||||||
f.description = this.description; // FIXME text vs html?
|
f.description = this.description; // FIXME text vs html?
|
||||||
f.lastUpdated = this.lastBuildDate; // FIXME: normalize format rss uses "Mon, 18 Nov 2019 12:00:00 GMT"
|
f.lastUpdated = this.lastBuildDate.rssDateToAtom;
|
||||||
|
|
||||||
foreach(item; items) {
|
foreach(item; items) {
|
||||||
Feed.Item fi;
|
Feed.Item fi;
|
||||||
|
@ -109,7 +161,7 @@ struct RssChannel {
|
||||||
fi.link = item.link;
|
fi.link = item.link;
|
||||||
fi.description = item.description; // FIXME: try to normalize text vs html
|
fi.description = item.description; // FIXME: try to normalize text vs html
|
||||||
fi.author = item.author; // FIXME
|
fi.author = item.author; // FIXME
|
||||||
fi.publicationDate = item.pubDate; // FIXME
|
fi.lastUpdatedDate = fi.publicationDate = item.pubDate.rssDateToAtom;
|
||||||
fi.guid = item.guid;
|
fi.guid = item.guid;
|
||||||
//fi.lastUpdatedDate; // not available i think
|
//fi.lastUpdatedDate; // not available i think
|
||||||
|
|
||||||
|
@ -258,16 +310,21 @@ struct AtomFeed {
|
||||||
|
|
||||||
feed.title = this.title;
|
feed.title = this.title;
|
||||||
feed.description = this.subtitle;
|
feed.description = this.subtitle;
|
||||||
feed.lastUpdated = this.updated; // FIXME: normalize the format is 2005-07-31T12:29:29Z
|
feed.lastUpdated = this.updated;
|
||||||
|
|
||||||
foreach(entry; this.entries) {
|
foreach(entry; this.entries) {
|
||||||
Feed.Item item;
|
Feed.Item item;
|
||||||
|
|
||||||
item.title = entry.title;
|
item.title = entry.title;
|
||||||
item.link = entry.link;
|
item.link = entry.link;
|
||||||
item.description = entry.summary.html.length ? entry.summary.html : entry.summary.text; // FIXME
|
if(entry.content.html.length || entry.content.text.length)
|
||||||
item.author = entry.author.email; // FIXME normalize; RSS does "email (name)"
|
item.description = entry.content.html.length ? entry.content.html : entry.content.text; // FIXME
|
||||||
item.publicationDate = entry.published; // FIXME the format is 2005-07-31T12:29:29Z
|
else
|
||||||
|
item.description = entry.summary.html.length ? entry.summary.html : entry.summary.text; // FIXME
|
||||||
|
item.author = entry.author.email;
|
||||||
|
if(entry.author.name.length)
|
||||||
|
item.author ~= " (" ~ entry.author.name ~ ")";
|
||||||
|
item.publicationDate = entry.published;
|
||||||
item.lastUpdatedDate = entry.updated;
|
item.lastUpdatedDate = entry.updated;
|
||||||
item.guid = entry.id;
|
item.guid = entry.id;
|
||||||
|
|
||||||
|
@ -384,6 +441,60 @@ AtomFeed parseAtom(string s) {
|
||||||
return parseAtom(document.root);
|
return parseAtom(document.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string rssDateToAtom(string d) {
|
||||||
|
auto orig = d;
|
||||||
|
if(d.length < 22 || d[3] != ',')
|
||||||
|
return orig; // doesn't appear to be the right format
|
||||||
|
d = d[5 .. $];
|
||||||
|
|
||||||
|
import std.conv;
|
||||||
|
auto day = parse!int(d);
|
||||||
|
if(d.length == 0 || d[0] != ' ')
|
||||||
|
return orig;
|
||||||
|
d = d[1 .. $];
|
||||||
|
|
||||||
|
if(d.length < 4)
|
||||||
|
return orig;
|
||||||
|
|
||||||
|
int month;
|
||||||
|
|
||||||
|
string months = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||||
|
foreach(i; 0 .. 12) {
|
||||||
|
if(months[i * 3 .. i * 3 + 3] == d[0 .. 3]) {
|
||||||
|
month = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d = d[4 .. $];
|
||||||
|
|
||||||
|
auto year = parse!int(d);
|
||||||
|
|
||||||
|
if(d.length == 0 || d[0] != ' ')
|
||||||
|
return orig;
|
||||||
|
d = d[1 .. $];
|
||||||
|
|
||||||
|
auto hour = parse!int(d);
|
||||||
|
|
||||||
|
if(d.length == 0 || d[0] != ':')
|
||||||
|
return orig;
|
||||||
|
d = d[1 .. $];
|
||||||
|
|
||||||
|
auto minute = parse!int(d);
|
||||||
|
|
||||||
|
if(d.length == 0 || d[0] != ':')
|
||||||
|
return orig;
|
||||||
|
d = d[1 .. $];
|
||||||
|
|
||||||
|
auto second = parse!int(d);
|
||||||
|
|
||||||
|
import std.format;
|
||||||
|
return format("%04d-%02d-%02dT%02d:%02d:%02dZ", year, month, day, hour, minute, second);
|
||||||
|
}
|
||||||
|
unittest {
|
||||||
|
assert(rssDateToAtom("Mon, 18 Nov 2019 12:05:44 GMT") == "2019-11-18T12:05:44Z");
|
||||||
|
}
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
|
|
||||||
auto test1 = `<?xml version="1.0" encoding="ISO-8859-1"?>
|
auto test1 = `<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
@ -647,6 +758,10 @@ auto testAtom1 = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
assert(e.entries[0].summary.html.length == 0);
|
assert(e.entries[0].summary.html.length == 0);
|
||||||
assert(e.entries[0].content.text.length == 0);
|
assert(e.entries[0].content.text.length == 0);
|
||||||
assert(e.entries[0].content.html.length > 10);
|
assert(e.entries[0].content.html.length > 10);
|
||||||
|
|
||||||
|
auto gf = e.toGenericFeed();
|
||||||
|
|
||||||
|
assert(gf.items[0].lastUpdatedDate == "2003-12-13T18:30:02Z");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -702,6 +817,8 @@ auto testAtom1 = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
auto gf = e.toGenericFeed();
|
auto gf = e.toGenericFeed();
|
||||||
assert(gf.items[0].link == "https://www.nytimes.com/2019/12/06/world/europe/france-pension-strike-macron.html?emc=rss&partner=rss", e.items[0].link);
|
assert(gf.items[0].link == "https://www.nytimes.com/2019/12/06/world/europe/france-pension-strike-macron.html?emc=rss&partner=rss", e.items[0].link);
|
||||||
|
|
||||||
|
assert(gf.items[0].publicationDate == "2019-12-06T18:02:13Z");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,6 +198,10 @@ interface->SetProgressValue(hwnd, 40, 100);
|
||||||
its specific implementation. If you disagree with how I did something, please contact me so we
|
its specific implementation. If you disagree with how I did something, please contact me so we
|
||||||
can discuss it!
|
can discuss it!
|
||||||
|
|
||||||
|
$(H2 Using with fibers)
|
||||||
|
|
||||||
|
simpledisplay can be used with [core.thread.Fiber], but be warned many of the functions can use a significant amount of stack space. I recommend at least 64 KB stack for each fiber (just set through the second argument to Fiber's constructor).
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
$(H3 Event-example)
|
$(H3 Event-example)
|
||||||
|
@ -1858,7 +1862,6 @@ class SimpleWindow : CapableOfHandlingNativeEvent, CapableOfBeingDrawnUpon {
|
||||||
version(Windows)
|
version(Windows)
|
||||||
ShowWindow(impl.hwnd, SW_MAXIMIZE);
|
ShowWindow(impl.hwnd, SW_MAXIMIZE);
|
||||||
else version(X11) {
|
else version(X11) {
|
||||||
// I actually could set both at once...
|
|
||||||
setNetWmStateAtom(this.impl.window, GetAtom!("_NET_WM_STATE_MAXIMIZED_VERT", false)(XDisplayConnection.get), true, GetAtom!("_NET_WM_STATE_MAXIMIZED_HORZ", false)(XDisplayConnection.get));
|
setNetWmStateAtom(this.impl.window, GetAtom!("_NET_WM_STATE_MAXIMIZED_VERT", false)(XDisplayConnection.get), true, GetAtom!("_NET_WM_STATE_MAXIMIZED_HORZ", false)(XDisplayConnection.get));
|
||||||
|
|
||||||
// also note _NET_WM_STATE_FULLSCREEN
|
// also note _NET_WM_STATE_FULLSCREEN
|
||||||
|
@ -1866,6 +1869,21 @@ class SimpleWindow : CapableOfHandlingNativeEvent, CapableOfBeingDrawnUpon {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _fullscreen;
|
||||||
|
|
||||||
|
/// not fully implemented but planned for a future release
|
||||||
|
void fullscreen(bool yes) {
|
||||||
|
version(X11)
|
||||||
|
setNetWmStateAtom(this.impl.window, GetAtom!("_NET_WM_STATE_FULLSCREEN", false)(XDisplayConnection.get), yes);
|
||||||
|
|
||||||
|
_fullscreen = yes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fullscreen() {
|
||||||
|
return _fullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
/++
|
/++
|
||||||
Note: only implemented on Windows. No-op on other platforms. You may want to use [hide] instead.
|
Note: only implemented on Windows. No-op on other platforms. You may want to use [hide] instead.
|
||||||
|
|
||||||
|
@ -1972,12 +1990,14 @@ class SimpleWindow : CapableOfHandlingNativeEvent, CapableOfBeingDrawnUpon {
|
||||||
width and height are actually changed.
|
width and height are actually changed.
|
||||||
+/
|
+/
|
||||||
void resize(int w, int h) {
|
void resize(int w, int h) {
|
||||||
|
if(!_closed && _fullscreen) fullscreen = false;
|
||||||
version(OSXCocoa) throw new NotYetImplementedException(); else
|
version(OSXCocoa) throw new NotYetImplementedException(); else
|
||||||
if (!_closed) impl.resize(w, h);
|
if (!_closed) impl.resize(w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move and resize window (this can be faster and more visually pleasant than doing it separately).
|
/// Move and resize window (this can be faster and more visually pleasant than doing it separately).
|
||||||
void moveResize (int x, int y, int w, int h) {
|
void moveResize (int x, int y, int w, int h) {
|
||||||
|
if(!_closed && _fullscreen) fullscreen = false;
|
||||||
version(OSXCocoa) throw new NotYetImplementedException(); else
|
version(OSXCocoa) throw new NotYetImplementedException(); else
|
||||||
if (!_closed) impl.moveResize(x, y, w, h);
|
if (!_closed) impl.moveResize(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
@ -18044,7 +18064,28 @@ struct DropPackage {
|
||||||
auto selectionAtom = GetAtom!"XdndSelection"(display);
|
auto selectionAtom = GetAtom!"XdndSelection"(display);
|
||||||
auto best = format;
|
auto best = format;
|
||||||
|
|
||||||
class X11GetSelectionHandler_Drop : X11GetSelectionHandler {
|
static class X11GetSelectionHandler_Drop : X11GetSelectionHandler {
|
||||||
|
|
||||||
|
XDisplay* display;
|
||||||
|
Atom selectionAtom;
|
||||||
|
DraggableData.FormatId best;
|
||||||
|
DraggableData.FormatId format;
|
||||||
|
void delegate(scope ubyte[] data) dg;
|
||||||
|
DragAndDropAction acceptedAction;
|
||||||
|
Window sourceWindow;
|
||||||
|
SimpleWindow win;
|
||||||
|
this(XDisplay* display, SimpleWindow win, Window sourceWindow, DraggableData.FormatId format, Atom selectionAtom, DraggableData.FormatId best, void delegate(scope ubyte[] data) dg, DragAndDropAction acceptedAction) {
|
||||||
|
this.display = display;
|
||||||
|
this.win = win;
|
||||||
|
this.sourceWindow = sourceWindow;
|
||||||
|
this.format = format;
|
||||||
|
this.selectionAtom = selectionAtom;
|
||||||
|
this.best = best;
|
||||||
|
this.dg = dg;
|
||||||
|
this.acceptedAction = acceptedAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
mixin X11GetSelectionHandler_Basics;
|
mixin X11GetSelectionHandler_Basics;
|
||||||
|
|
||||||
void handleData(Atom target, in ubyte[] data) {
|
void handleData(Atom target, in ubyte[] data) {
|
||||||
|
@ -18063,7 +18104,7 @@ struct DropPackage {
|
||||||
xclient.format = 32;
|
xclient.format = 32;
|
||||||
xclient.data.l[0] = win.impl.window;
|
xclient.data.l[0] = win.impl.window;
|
||||||
xclient.data.l[1] = 1; // drop successful
|
xclient.data.l[1] = 1; // drop successful
|
||||||
xclient.data.l[2] = GetAtom!"XdndActionCopy"(display); // FIXME: actual accepted action
|
xclient.data.l[2] = dndActionAtom(display, acceptedAction);
|
||||||
|
|
||||||
XSendEvent(
|
XSendEvent(
|
||||||
display,
|
display,
|
||||||
|
@ -18072,6 +18113,8 @@ struct DropPackage {
|
||||||
EventMask.NoEventMask,
|
EventMask.NoEventMask,
|
||||||
cast(XEvent*) &xclient
|
cast(XEvent*) &xclient
|
||||||
);
|
);
|
||||||
|
|
||||||
|
XFlush(display);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18097,7 +18140,7 @@ struct DropPackage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
win.impl.getSelectionHandlers[selectionAtom] = new X11GetSelectionHandler_Drop();
|
win.impl.getSelectionHandlers[selectionAtom] = new X11GetSelectionHandler_Drop(display, win, sourceWindow, format, selectionAtom, best, dg, acceptedAction);
|
||||||
|
|
||||||
XConvertSelection(display, selectionAtom, best, GetAtom!("SDD_DATA", true)(display), win.impl.window, dataTimestamp);
|
XConvertSelection(display, selectionAtom, best, GetAtom!("SDD_DATA", true)(display), win.impl.window, dataTimestamp);
|
||||||
|
|
||||||
|
@ -18197,8 +18240,10 @@ class GenericDropHandlerBase : DropHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
void drop(scope DropPackage* dropPackage) {
|
void drop(scope DropPackage* dropPackage) {
|
||||||
if(!acceptedFormat || acceptedHandler is null)
|
if(!acceptedFormat || acceptedHandler is null) {
|
||||||
|
debug(sdpy_dnd) { import std.stdio; writeln("drop called w/ handler ", acceptedHandler, " and format ", acceptedFormat); }
|
||||||
return; // prolly shouldn't happen anyway...
|
return; // prolly shouldn't happen anyway...
|
||||||
|
}
|
||||||
|
|
||||||
dropPackage.getData(acceptedAction, acceptedFormat, acceptedHandler);
|
dropPackage.getData(acceptedAction, acceptedFormat, acceptedHandler);
|
||||||
}
|
}
|
||||||
|
|
27
terminal.d
27
terminal.d
|
@ -174,6 +174,20 @@ import core.stdc.stdio;
|
||||||
|
|
||||||
version(TerminalDirectToEmulator) {
|
version(TerminalDirectToEmulator) {
|
||||||
version=WithEncapsulatedSignals;
|
version=WithEncapsulatedSignals;
|
||||||
|
private __gshared bool windowGone = false;
|
||||||
|
private bool forceTerminationTried = false;
|
||||||
|
private void forceTermination() {
|
||||||
|
if(forceTerminationTried) {
|
||||||
|
// why are we still here?! someone must be catching the exception and calling back.
|
||||||
|
// there's no recovery so time to kill this program.
|
||||||
|
import core.stdc.stdlib;
|
||||||
|
abort();
|
||||||
|
} else {
|
||||||
|
// give them a chance to cleanly exit...
|
||||||
|
forceTerminationTried = true;
|
||||||
|
throw new HangupException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version(Posix) {
|
version(Posix) {
|
||||||
|
@ -2705,6 +2719,7 @@ struct RealTimeConsoleInput {
|
||||||
import core.time;
|
import core.time;
|
||||||
if(terminal.tew.terminalEmulator.pendingForApplication.length)
|
if(terminal.tew.terminalEmulator.pendingForApplication.length)
|
||||||
return true;
|
return true;
|
||||||
|
if(windowGone) forceTermination();
|
||||||
if(terminal.tew.terminalEmulator.outgoingSignal.wait(milliseconds.msecs))
|
if(terminal.tew.terminalEmulator.outgoingSignal.wait(milliseconds.msecs))
|
||||||
// it was notified, but it could be left over from stuff we
|
// it was notified, but it could be left over from stuff we
|
||||||
// already processed... so gonna check the blocking conditions here too
|
// already processed... so gonna check the blocking conditions here too
|
||||||
|
@ -2795,8 +2810,10 @@ struct RealTimeConsoleInput {
|
||||||
moar:
|
moar:
|
||||||
//if(interruptable && inputQueue.length)
|
//if(interruptable && inputQueue.length)
|
||||||
//return -1;
|
//return -1;
|
||||||
if(terminal.tew.terminalEmulator.pendingForApplication.length == 0)
|
if(terminal.tew.terminalEmulator.pendingForApplication.length == 0) {
|
||||||
|
if(windowGone) forceTermination();
|
||||||
terminal.tew.terminalEmulator.outgoingSignal.wait();
|
terminal.tew.terminalEmulator.outgoingSignal.wait();
|
||||||
|
}
|
||||||
synchronized(terminal.tew.terminalEmulator) {
|
synchronized(terminal.tew.terminalEmulator) {
|
||||||
if(terminal.tew.terminalEmulator.pendingForApplication.length == 0) {
|
if(terminal.tew.terminalEmulator.pendingForApplication.length == 0) {
|
||||||
if(interruptable)
|
if(interruptable)
|
||||||
|
@ -5626,6 +5643,7 @@ class LineGetter {
|
||||||
terminal.tew.terminalEmulator.waitingForInboundSync = true;
|
terminal.tew.terminalEmulator.waitingForInboundSync = true;
|
||||||
terminal.writeStringRaw("\xff");
|
terminal.writeStringRaw("\xff");
|
||||||
terminal.flush();
|
terminal.flush();
|
||||||
|
if(windowGone) forceTermination();
|
||||||
terminal.tew.terminalEmulator.syncSignal.wait();
|
terminal.tew.terminalEmulator.syncSignal.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7822,8 +7840,10 @@ version(TerminalDirectToEmulator) {
|
||||||
terminalEmulator = new TerminalEmulatorInsideWidget(this);
|
terminalEmulator = new TerminalEmulatorInsideWidget(this);
|
||||||
super(parent);
|
super(parent);
|
||||||
this.parentWindow.win.onClosing = {
|
this.parentWindow.win.onClosing = {
|
||||||
if(term)
|
if(term) {
|
||||||
term.hangedUp = true;
|
term.hangedUp = true;
|
||||||
|
// should I just send an official SIGHUP?!
|
||||||
|
}
|
||||||
|
|
||||||
if(auto wi = cast(TerminalEmulatorWindow) this.parentWindow) {
|
if(auto wi = cast(TerminalEmulatorWindow) this.parentWindow) {
|
||||||
if(wi.parent)
|
if(wi.parent)
|
||||||
|
@ -7860,6 +7880,8 @@ version(TerminalDirectToEmulator) {
|
||||||
terminalEmulator.outgoingSignal.notify();
|
terminalEmulator.outgoingSignal.notify();
|
||||||
terminalEmulator.incomingSignal.notify();
|
terminalEmulator.incomingSignal.notify();
|
||||||
terminalEmulator.syncSignal.notify();
|
terminalEmulator.syncSignal.notify();
|
||||||
|
|
||||||
|
windowGone = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.parentWindow.win.addEventListener((InputEventInternal ie) {
|
this.parentWindow.win.addEventListener((InputEventInternal ie) {
|
||||||
|
@ -7875,6 +7897,7 @@ version(TerminalDirectToEmulator) {
|
||||||
void sendRawInput(const(ubyte)[] data) {
|
void sendRawInput(const(ubyte)[] data) {
|
||||||
if(this.parentWindow) {
|
if(this.parentWindow) {
|
||||||
this.parentWindow.win.postEvent(new InputEventInternal(data));
|
this.parentWindow.win.postEvent(new InputEventInternal(data));
|
||||||
|
if(windowGone) forceTermination();
|
||||||
terminalEmulator.incomingSignal.wait(); // blocking write basically, wait until the TE confirms the receipt of it
|
terminalEmulator.incomingSignal.wait(); // blocking write basically, wait until the TE confirms the receipt of it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1311,7 +1311,11 @@ class TerminalEmulator {
|
||||||
(esc[0] == '[' && (b >= 64 && b <= 126)) ||
|
(esc[0] == '[' && (b >= 64 && b <= 126)) ||
|
||||||
(esc[0] == ']' && b == '\007')))
|
(esc[0] == ']' && b == '\007')))
|
||||||
{
|
{
|
||||||
tryEsc(esc[]);
|
try {
|
||||||
|
tryEsc(esc[]);
|
||||||
|
} catch(Exception e) {
|
||||||
|
unknownEscapeSequence(e.msg ~ " :: " ~ cast(char[]) esc[]);
|
||||||
|
}
|
||||||
esc = null;
|
esc = null;
|
||||||
readingEsc = false;
|
readingEsc = false;
|
||||||
} else if(esc.length == 3 && esc[0] == '%' && esc[1] == 'G') {
|
} else if(esc.length == 3 && esc[0] == '%' && esc[1] == 'G') {
|
||||||
|
@ -1625,16 +1629,44 @@ class TerminalEmulator {
|
||||||
notifyScrollbarPosition(currentScrollbackX, currentScrollback ? scrollbackLength - currentScrollback : int.max);
|
notifyScrollbarPosition(currentScrollbackX, currentScrollback ? scrollbackLength - currentScrollback : int.max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/++
|
||||||
|
Writes the text in the scrollback buffer to the given file.
|
||||||
|
|
||||||
|
Discards formatting information and embedded images.
|
||||||
|
|
||||||
|
See_Also:
|
||||||
|
[writeScrollbackToDelegate]
|
||||||
|
+/
|
||||||
public void writeScrollbackToFile(string filename) {
|
public void writeScrollbackToFile(string filename) {
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
auto file = File(filename, "wt");
|
auto file = File(filename, "wt");
|
||||||
foreach(line; scrollbackBuffer[]) {
|
foreach(line; scrollbackBuffer[]) {
|
||||||
foreach(c; line)
|
foreach(c; line)
|
||||||
file.write(c.ch); // I hope this is buffered
|
if(!c.hasNonCharacterData)
|
||||||
|
file.write(c.ch); // I hope this is buffered
|
||||||
file.writeln();
|
file.writeln();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/++
|
||||||
|
Writes the text in the scrollback buffer to the given delegate, one character at a time.
|
||||||
|
|
||||||
|
Discards formatting information and embedded images.
|
||||||
|
|
||||||
|
See_Also:
|
||||||
|
[writeScrollbackToFile]
|
||||||
|
History:
|
||||||
|
Added March 14, 2021 (dub version 9.4)
|
||||||
|
+/
|
||||||
|
public void writeScrollbackToDelegate(scope void delegate(dchar c) dg) {
|
||||||
|
foreach(line; scrollbackBuffer[]) {
|
||||||
|
foreach(c; line)
|
||||||
|
if(!c.hasNonCharacterData)
|
||||||
|
dg(c.ch);
|
||||||
|
dg('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void drawScrollback(bool useAltScreen = false) {
|
public void drawScrollback(bool useAltScreen = false) {
|
||||||
showScrollbackOnScreen(useAltScreen ? alternateScreen : normalScreen, 0, true, 0);
|
showScrollbackOnScreen(useAltScreen ? alternateScreen : normalScreen, 0, true, 0);
|
||||||
}
|
}
|
||||||
|
@ -1836,6 +1868,13 @@ class TerminalEmulator {
|
||||||
bool mouseButtonReleaseTracking;
|
bool mouseButtonReleaseTracking;
|
||||||
bool mouseButtonMotionTracking;
|
bool mouseButtonMotionTracking;
|
||||||
bool selectiveMouseTracking;
|
bool selectiveMouseTracking;
|
||||||
|
/+
|
||||||
|
When set, it causes xterm to send CSI I when the terminal gains focus, and CSI O when it loses focus.
|
||||||
|
this is turned on by mode 1004 with mouse events.
|
||||||
|
|
||||||
|
FIXME: not implemented.
|
||||||
|
+/
|
||||||
|
bool sendFocusEvents;
|
||||||
|
|
||||||
bool mouseMotionTracking() {
|
bool mouseMotionTracking() {
|
||||||
return _mouseMotionTracking;
|
return _mouseMotionTracking;
|
||||||
|
@ -1851,6 +1890,7 @@ class TerminalEmulator {
|
||||||
mouseButtonTracking = false;
|
mouseButtonTracking = false;
|
||||||
mouseButtonReleaseTracking = false;
|
mouseButtonReleaseTracking = false;
|
||||||
mouseButtonMotionTracking = false;
|
mouseButtonMotionTracking = false;
|
||||||
|
sendFocusEvents = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wraparoundMode = true;
|
bool wraparoundMode = true;
|
||||||
|
@ -2337,7 +2377,13 @@ class TerminalEmulator {
|
||||||
return bfr[0 .. max(argsAtSidx[sidx - 1].length, defaults.length)];
|
return bfr[0 .. max(argsAtSidx[sidx - 1].length, defaults.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto argsSection = cast(char[]) esc[sidx .. $-1];
|
auto end = esc.length - 1;
|
||||||
|
foreach(iii, b; esc[sidx .. end]) {
|
||||||
|
if(b >= 0x20 && b < 0x30)
|
||||||
|
end = iii + sidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto argsSection = cast(char[]) esc[sidx .. end];
|
||||||
int[] args = argsAtSidxBuffer[sidx - 1][];
|
int[] args = argsAtSidxBuffer[sidx - 1][];
|
||||||
|
|
||||||
import std.string : split;
|
import std.string : split;
|
||||||
|
@ -2995,6 +3041,9 @@ P s = 2 3 ; 2 → Restore xterm window title from stack.
|
||||||
mouseButtonReleaseTracking = true;
|
mouseButtonReleaseTracking = true;
|
||||||
mouseMotionTracking = true;
|
mouseMotionTracking = true;
|
||||||
break;
|
break;
|
||||||
|
case 1004:
|
||||||
|
sendFocusEvents = true;
|
||||||
|
break;
|
||||||
case 1005:
|
case 1005:
|
||||||
// enable utf-8 mouse mode
|
// enable utf-8 mouse mode
|
||||||
/*
|
/*
|
||||||
|
@ -3102,6 +3151,9 @@ URXVT (1015)
|
||||||
case 34:
|
case 34:
|
||||||
// no idea. vim inside screen sends it
|
// no idea. vim inside screen sends it
|
||||||
break;
|
break;
|
||||||
|
case 1004:
|
||||||
|
sendFocusEvents = false;
|
||||||
|
break;
|
||||||
case 1005:
|
case 1005:
|
||||||
// turn off utf-8 mouse
|
// turn off utf-8 mouse
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue