Skip to content

Commit

Permalink
[Feat] finished codesnap client
Browse files Browse the repository at this point in the history
  • Loading branch information
mistricky committed Feb 21, 2024
1 parent f8773e5 commit 383be3a
Show file tree
Hide file tree
Showing 19 changed files with 1,764 additions and 122 deletions.
8 changes: 5 additions & 3 deletions lua/codesnap/client.lua
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
local logger = require("codesnap.utils.logger")
local path_utils = require("codesnap.utils.path")
local static = require("codesnap.static")

local client = {
job_id = 0,
}

local cwd = static.cwd .. "/snap-server"

function client:connect()
return vim.fn.jobstart({
path_utils.back(path_utils.back(debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])")))
.. "/snap-server/target/debug/snap-server",
cwd .. "/target/release/snap-server",
}, {
cwd = cwd,
stderr_buffered = true,
rpc = true,
on_stderr = function(_, err)
Expand Down
17 changes: 12 additions & 5 deletions lua/codesnap/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ local static = require("codesnap.static")
local client = require("codesnap.client")
local visual_utils = require("codesnap.utils.visual")

local main = {}
local main = {
cwd = static.cwd,
preview_switch = static.preview_switch,
}

function main.setup(config)
static.config = table_utils.merge(static.config, config == nil and {} or config)

print(vim.inspect(static.config))
print(table_utils.serialize_json(static.config))
print()

if static.config.auto_load then
client:start()
end
Expand All @@ -23,4 +22,12 @@ function main.preview_code()
client:send("preview_code", { content = visual_utils.get_selected_text(), language = vim.bo.filetype })
end

function main.open_preview()
client:send("open_preview")
end

function main.stop_client()
client:stop()
end

return main
5 changes: 3 additions & 2 deletions lua/codesnap/static.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
local path_utils = require("codesnap.utils.path")

return {
config = {
breadcrumbs = true,
column_number = true,
mac_window_bar = true,
opacity = true,
watermark = "CodeSnap.nvim",
auto_load = true,
},
cwd = path_utils.back(path_utils.back(debug.getinfo(1, "S").source:sub(2):match("(.*[/\\])"))),
preview_switch = true,
}
20 changes: 20 additions & 0 deletions plugin/build.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
local codesnap = require("codesnap")
local snap_client_cwd = codesnap.cwd .. "/snap-client"
local snap_server_cwd = codesnap.cwd .. "/snap-server"

-- Build preview client
os.execute(
"cd "
.. snap_client_cwd
.. " && "
.. "npm i "
.. " && "
.. "npm run build"
.. " && "
.. "mv ./build "
.. snap_server_cwd
.. "/public"
)

-- Build server
os.execute("cd " .. snap_server_cwd .. " && " .. "cargo build --release")
18 changes: 9 additions & 9 deletions plugin/codesnap.lua
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
local codesnap = require("codesnap")
local static = require("codesnap.static")
local client = require("codesnap.client")
-- local client = require("codesnap.client")

-- snap code
vim.api.nvim_create_user_command("CodeSnap", function() end, {})
-- vim.api.nvim_create_user_command("CodeSnap", function()
-- client:send("copy")
-- end, {})

vim.api.nvim_create_user_command("CodeSnapPreviewOn", function() end, {})

vim.api.nvim_create_user_command("CodeSnapPreviewOff", function() end, {})
vim.api.nvim_create_user_command("CodeSnapPreviewOn", function()
codesnap.open_preview()
end, {})

vim.api.nvim_create_autocmd({ "CursorMoved" }, {
callback = function()
local mode = vim.api.nvim_get_mode().mode

if mode ~= "v" or not static.preview_switch then
if mode ~= "v" or not codesnap.preview_switch then
return
end

Expand All @@ -24,6 +24,6 @@ vim.api.nvim_create_autocmd({ "CursorMoved" }, {
vim.api.nvim_create_autocmd({ "VimLeavePre" }, {
pattern = "*",
callback = function()
client:stop()
codesnap.stop_client()
end,
})
48 changes: 35 additions & 13 deletions snap-client/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import useWebSocket, { ReadyState } from "react-use-websocket";
import { ControlBar, Editor, Frame, Panel } from "./components";
import { useConfig, useEvent } from "./hooks";
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from "html-to-image";
import { toPng, toBlob } from "html-to-image";
import download from "downloadjs";

const CODE_EMPTY_PLACEHOLDER = `print "Hello, CodeSnap.nvim!"`;

function App() {
const [socketUrl] = useState("ws://127.0.0.1:8080/ws");
const [socketUrl] = useState(`ws://${window.location.host}/ws`);
const { sendMessage, lastMessage, readyState } = useWebSocket(socketUrl);
const event = useEvent(lastMessage);
const config = useConfig(event?.config_setup);
const frameRef = useRef<HTMLDivElement | null>(null);
const [isCopyButtonDisabled, setIsCopyButtonDisabled] = useState(false);

const handleCopyButtonClick = useCallback(async () => {
if (!frameRef.current) {
return;
}

const blob = await toBlob(frameRef.current);
const clipboardItem = new ClipboardItem({ "image/png": blob! });
setIsCopyButtonDisabled(true);

navigator.clipboard.write([clipboardItem]);
try {
const blob = await toBlob(frameRef.current);
const clipboardItem = new ClipboardItem({ "image/png": blob! });

navigator.clipboard.write([clipboardItem]);
} catch (e) {
console.error(e);
} finally {
setIsCopyButtonDisabled(false);
}
}, []);

const handleExportClick = useCallback(async () => {
Expand All @@ -41,18 +44,37 @@ function App() {
download(dataURL, "codesnap.png");
}, []);

const notifyCopyCommand = useCallback(async () => {
if (!frameRef.current) {
return;
}

const dataURL = await toPng(frameRef.current);

sendMessage(dataURL);
}, [sendMessage]);

useEffect(() => {
if (readyState !== ReadyState.OPEN || !event?.copy) {
return;
}

notifyCopyCommand();
}, [event, readyState, notifyCopyCommand]);

return (
<div className="w-full h-full flex flex-col items-center bg-deep-gray">
<p className="rainbow-text text-4xl font-extrabold mt-20">
CodeSnap.nvim
</p>
<Panel>
<ControlBar
isCopyButtonDisabled={isCopyButtonDisabled}
onExportClick={handleExportClick}
onCopyClick={handleCopyButtonClick}
readyState={readyState}
/>
<div className="rounded-xl overflow-hidden">
<div id="frame" className="rounded-xl overflow-hidden">
<Frame ref={frameRef} watermark={config?.watermark}>
<Editor
language={event?.code?.language}
Expand Down
53 changes: 53 additions & 0 deletions snap-client/src/components/control-bar/connection-status.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useMemo } from "react";
import { ReadyState } from "react-use-websocket";

interface ConnectionStatusProps {
readyState: ReadyState;
}

const CONNECTION_STATUS_MAP = {
[ReadyState.CONNECTING]: {
text: "Connecting",
color: "#fdcb6e",
},
[ReadyState.OPEN]: {
text: "Connected",
color: "#00b894",
},
[ReadyState.CLOSING]: {
text: "Closing",
color: "#fab1a0",
},
[ReadyState.CLOSED]: {
text: "Closed",
color: "#636e72",
},
[ReadyState.UNINSTANTIATED]: {
text: "Uninstantiated",
color: "#2d3436",
},
} as const;

const UNKNOWN_STATE = { text: "Unknown", color: "#a29bfe" };

export const ConnectionStatus = ({ readyState }: ConnectionStatusProps) => {
const parsedState = useMemo(
() => CONNECTION_STATUS_MAP[readyState] ?? UNKNOWN_STATE,
[readyState],
);

return (
<div className="flex flex-grow flex-row items-center mr-1 ml-2">
<div
className="flex w-5 h-5 mr-2 justify-center items-center rounded-full"
style={{ backgroundColor: `${parsedState.color}50` }}
>
<div
className="w-3 h-3 rounded-full"
style={{ backgroundColor: parsedState.color }}
></div>
</div>
{parsedState.text}
</div>
);
};
13 changes: 8 additions & 5 deletions snap-client/src/components/control-bar/control-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ConnectionStatus } from "./connection-status";
import { ReadyState } from "react-use-websocket";

interface ControlBarProps {
isCopyButtonDisabled: boolean;
onCopyClick(): void;
onExportClick(): void;
readyState: ReadyState;
Expand All @@ -10,13 +11,11 @@ interface ControlBarProps {
export const ControlBar = ({
onCopyClick,
onExportClick,
isCopyButtonDisabled,
readyState,
}: ControlBarProps) => {
return (
<div
className="bg-neutral rounded-xl mb-2 p-1 flex flex-row items-center"
onClick={onCopyClick}
>
<div className="bg-neutral rounded-xl mb-2 p-1 flex flex-row items-center">
<ConnectionStatus readyState={readyState} />
<div className="flex flex-row items-center">
{/*
Expand Down Expand Up @@ -44,7 +43,11 @@ export const ControlBar = ({
<path d="M480-320 280-520l56-58 104 104v-326h80v326l104-104 56 58-200 200ZM240-160q-33 0-56.5-23.5T160-240v-120h80v120h480v-120h80v120q0 33-23.5 56.5T720-160H240Z" />
</svg>
</button>
<button className="btn">
<button
onClick={onCopyClick}
id="copy"
className={`btn ${isCopyButtonDisabled && "btn-disabled"}`}
>
Copy
<svg
className="fill-neutral-content"
Expand Down
2 changes: 0 additions & 2 deletions snap-client/src/hooks/use-config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { useLocalStorage } from "./use-storage";

export interface Config {
breadcrumbs: boolean;
column_number: boolean;
mac_window_bar: boolean;
opacity: boolean;
watermark: string;
Expand Down
2 changes: 2 additions & 0 deletions snap-client/src/hooks/use-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Config } from "./use-config";
export enum EventType {
CONFIG_SETUP = "config_setup",
CODE = "code",
COPY = "copy",
}

type CodeMessage = {
Expand All @@ -14,6 +15,7 @@ type CodeMessage = {
type ParsedConfig = {
[EventType.CODE]: CodeMessage;
[EventType.CONFIG_SETUP]: Config;
[EventType.COPY]: undefined;
};

export const useEvent = (
Expand Down
Loading

0 comments on commit 383be3a

Please sign in to comment.