页面 动态显示cmd执行结果_把代码执行演示嵌在你的PPT中

本文介绍如何在演示中实现代码实时运行,通过Microsoft PowerPoint、Glot Code Runner和Docker构建一个可以在PPT中嵌入并运行Python代码的解决方案,提升技术分享效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

aaafc9d62451f40cccfd671cedd3c63d.png

“Talk is cheap, show me your code!”

当一个程序员在做技术分享的时候, 代码演示经常是不可或缺的一个环节。然而在你的演示PPT和代码运行之间切换是一件非常恼人事情,而且非常影响演示的节奏和流畅性。要做一个完美的技术分享,能不能把代码的运行嵌入到PPT中呢?

当然可以,我前不久(几年前把 )在公司内部分享了一起关于Python的小谜题,大家可以到斗鱼去观看这次分享的视频录播 (很糟糕的是在36分钟后,摄像头偏移了,拍了大半天挂钟)

为了实现代码嵌入ppt,我用到的关键技术包括:

  • Microsoft PowerPoint
  • Glot Code Runner
  • Docker

首先,演示常用的是微软的PowerPoint(至于苹果的Keynote,我暂时还没有找到解决方案),所以你需要安装PowerPoint,在最新的Office套件中,微软提供了一个Webview的插件,有了这个插件,可以直接把一个Web页面,嵌入到Office文档中,自然也就包含了PPT。

6cb6e3dc7a2fbaa65a8711e4eca92a03.png

注意,为了安全性的考虑,嵌入的web页面必须是https的。

好了有了这个,我们就可以把一个代码运行的web页面直接嵌入到演示文档中,剩下的事情,就是做一个可以运行不同代码的Web应用了。

Glot 是一个开源的在线代码运行平台。其架构如下图所示。

bbf6ba1c5b0527698ce3eea8ca2290b8.png

利用Glot的代码运行的核心功能,我们就可以很方便的开发一个可以运行各种代码的web应用。

利用容器,我们可以把整个应用分为以下的几个层次:

  • Base
    提供基本的代码运行的环境,包含了代码执行的必要的解释器和编译器。在本次演示中,我使用了golang:latest,但是碰巧的是这个镜像是拥有Python的解释器的,我的代码演示都是python,省去了我安装Python的步骤。如果是别的不同的语言的演示,注意安装对应的环境。
  • Code Runner https://github.com/gangtao/code_runner
    我的Code Runner是对Glot的Code Runner的一个增强,该项目提供一个运行代码的服务。
    项目的Dockerfile:
FROM golang:latest

MAINTAINER gangtao@outlook.com

ENV GOPATH=/home/glot
ENV GOROOT=/usr/local/go

# Add user
RUN groupadd glot
RUN useradd -m -d /home/glot -g glot -s /bin/bash glot

# Copy files
Add ./build/release/server /home/glot/
# Add ./vendor/. /home/glot/src

USER glot
WORKDIR /home/glot/

# generate certificate
RUN go run $GOROOT/src/crypto/tls/generate_cert.go --host localhost

EXPOSE 8080

# CMD ["/home/glot/runner"]
ENTRYPOINT ["/home/glot/server"]

  • 通过Dockerfile我们可以看出该项目主要的内容:利用Glot实现代码运行,产生证书用于https,利用echo实现web 服务。
    Web服务的代码如下:
package code_runner

import (
	"fmt"
	"github.com/prasmussen/glot-code-runner/cmd"
	"github.com/prasmussen/glot-code-runner/language"
	"io/ioutil"
	"os"
	"path/filepath"
)

type Payload struct {
	Language string          `json:"language"`
	Files    []*InMemoryFile `json:"files"`
	Stdin    string          `json:"stdin"`
	Command  string          `json:"command"`
}

type InMemoryFile struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

type Result struct {
	Stdout string `json:"stdout"`
	Stderr string `json:"stderr"`
	Error  string `json:"error"`
}

func Run(payload *Payload) *Result {
	// Ensure that we have at least one file
	if len(payload.Files) == 0 {
		exitF("No files givenn")
	}

	// Check if we support given language
	if !language.IsSupported(payload.Language) {
		exitF("Language '%s' is not supportedn", payload.Language)
	}

	// Write files to disk
	filepaths, err := writeFiles(payload.Files)
	if err != nil {
		exitF("Failed to write file to disk (%s)", err.Error())
	}

	var stdout, stderr string

	// Execute the given command or run the code with
	// the language runner if no command is given
	if payload.Command == "" {
		stdout, stderr, err = language.Run(payload.Language, filepaths, payload.Stdin)
	} else {
		workDir := filepath.Dir(filepaths[0])
		stdout, stderr, err = cmd.RunBashStdin(workDir, payload.Command, payload.Stdin)
	}

	result := &Result{
		Stdout: stdout,
		Stderr: stderr,
		Error:  errToStr(err),
	}

	return result
}

// Writes files to disk, returns list of absolute filepaths
func writeFiles(files []*InMemoryFile) ([]string, error) {
	// Create temp dir
	tmpPath, err := ioutil.TempDir("", "")
	if err != nil {
		return nil, err
	}

	paths := make([]string, len(files), len(files))
	for i, file := range files {
		path, err := writeFile(tmpPath, file)
		if err != nil {
			return nil, err
		}

		paths[i] = path

	}
	return paths, nil
}

// Writes a single file to disk
func writeFile(basePath string, file *InMemoryFile) (string, error) {
	// Get absolute path to file inside basePath
	absPath := filepath.Join(basePath, file.Name)

	// Create all parent dirs
	err := os.MkdirAll(filepath.Dir(absPath), 0775)
	if err != nil {
		return "", err
	}

	// Write file to disk
	err = ioutil.WriteFile(absPath, []byte(file.Content), 0664)
	if err != nil {
		return "", err
	}

	// Return absolute path to file
	return absPath, nil
}

func exitF(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
	os.Exit(1)
}

func errToStr(err error) string {
	if err != nil {
		return err.Error()
	}

	return ""
}
  • 可以通过容器方便的启动该服务,然后就可以通过Rest请求,执行Python(Golang)的代码。
curl 
  -X POST 
  http://localhost:8080/run 
  -H 'Content-Type: application/json' 
  -d '{"language":"python","files":[{"name":"main.py","content":"print(42)"}]}'

{"stdout":"42n","stderr":"","error":""}
  • 在这个项目中,我用了echo来实现一个轻量级的Web服务,而没有使用Glot自带的基于Ruby的服务,这样做的好处是技术栈的统一,因为echo和glot的核心都是用的Golang。
  • Code Runner Web https://github.com/gangtao/code_runner_web
    有了服务,下面就是前端的UI了。
    UI使用了codemirror来做编辑器。Dockerfile如下:
FROM naughtytao/code_runner

MAINTAINER gangtao@outlook.com

Add ./static /home/glot/static
  • 运行Code Runner Web后,就可以在以下的web界面中输入你想要运行的结果,并实时的显示想要运行的结果了。

dc8815ca78ffc3811b8323519b5859d4.png

好了,剩下的还有一些事情要做,就是准备你的演示代码,大家可以参考这个项目,这里缺省是将所有的代码片段放在code/python/ 目录下。运行:http://localhost:8080/#2 就会加载第二个代码片段。

这个是嵌入后的效果:

5dfdc38e3f7518250b0bcf023a73068b.png

好了,是不是很Coooooool呢?

另外利用容器来构建应用真的非常非常方便。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值