日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

微软 VSCode IDE 源码分析揭秘

發(fā)布時(shí)間:2024/2/28 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 微软 VSCode IDE 源码分析揭秘 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作者:zanewang,騰訊 CSIG 工程師


目錄

  • (1)簡介

  • (2)技術(shù)架構(gòu)

  • (3)啟動(dòng)主進(jìn)程

  • (4)實(shí)例化服務(wù)

  • (5)事件分發(fā)

  • (6)進(jìn)程通信

  • (7)主要窗口

  • (8)開發(fā)調(diào)試


1.簡介

Visual Studio Code(簡稱 VSCode) 是開源免費(fèi)的 IDE 編輯器,原本是微軟內(nèi)部使用的云編輯器(Monaco)。

git 倉庫地址:https://github.com/microsoft/vscode

通過 Eletron 集成了桌面應(yīng)用,可以跨平臺(tái)使用,開發(fā)語言主要采用微軟自家的 TypeScript。
整個(gè)項(xiàng)目結(jié)構(gòu)比較清晰,方便閱讀代碼理解。成為了最流行跨平臺(tái)的桌面 IDE 應(yīng)用

微軟希望 VSCode 在保持核心輕量級(jí)的基礎(chǔ)上,增加項(xiàng)目支持,智能感知,編譯調(diào)試。


編譯安裝

下載最新版本,目前我用的是 1.37.1 版本
官方的 wiki 中有編譯安裝的說明 How to Contribute

Linux, Window, MacOS 三個(gè)系統(tǒng)編譯時(shí)有些差別,參考官方文檔,
在編譯安裝依賴時(shí)如果遇到 connect timeout, 需要進(jìn)行科學(xué)上網(wǎng)。

需要注意的一點(diǎn) 運(yùn)行環(huán)境依賴版本 Nodejs x64 version >= 10.16.0, < 11.0.0, python 2.7(3.0 不能正常執(zhí)行)


2.技術(shù)架構(gòu)

Electron

Electron 是一個(gè)使用 JavaScript, HTML 和 CSS 等 Web 技術(shù)創(chuàng)建原生程序的框架,它負(fù)責(zé)比較難搞的部分,你只需把精力放在你的應(yīng)用的核心上即可 (Electron = Node.js + Chromium + Native API)

Monaco Editor

Monaco Editor是微軟開源項(xiàng)目, 為 VS Code 提供支持的代碼編輯器,運(yùn)行在瀏覽器環(huán)境中。編輯器提供代碼提示,智能建議等功能。供開發(fā)人員遠(yuǎn)程更方便的編寫代碼,可獨(dú)立運(yùn)行。

TypeScript

TypeScript是一種由微軟開發(fā)的自由和開源的編程語言。它是 JavaScript 的一個(gè)超集,而且本質(zhì)上向這個(gè)語言添加了可選的靜態(tài)類型和基于類的面向?qū)ο缶幊?/p>


目錄結(jié)構(gòu)

├──?build?????????#?gulp編譯構(gòu)建腳本 ├──?extensions????#?內(nèi)置插件 ├──?product.json??#?App?meta信息 ├──?resources?????#?平臺(tái)相關(guān)靜態(tài)資源 ├──?scripts???????#?工具腳本,開發(fā)/測(cè)試 ├──?src???????????#?源碼目錄 └──?typings???????#?函數(shù)語法補(bǔ)全定義 └──?vs├──?base????????#?通用工具/協(xié)議和UI庫│???├──?browser?#?基礎(chǔ)UI組件,DOM操作│???├──?common??#?diff描述,markdown解析器,worker協(xié)議,各種工具函數(shù)│???├──?node????#?Node工具函數(shù)│???├──?parts???#?IPC協(xié)議(Electron、Node),quickopen、tree組件│???├──?test????#?base單測(cè)用例│???└──?worker??# Worker factory和main Worker(運(yùn)行IDE Core:Monaco)├──?code????????#?VSCode主運(yùn)行窗口├──?editor????????#?IDE代碼編輯器|???├──?browser?????#?代碼編輯器核心|???├──?common??????#?代碼編輯器核心|???├──?contrib?????#?vscode?與獨(dú)立?IDE共享的代碼|???└──?standalone??#?獨(dú)立?IDE?獨(dú)有的代碼├──?platform??????#?支持注入服務(wù)和平臺(tái)相關(guān)基礎(chǔ)服務(wù)(文件、剪切板、窗體、狀態(tài)欄)├──?workbench?????#?工作區(qū)UI布局,功能主界面│???├──?api??????????????#│???├──?browser??????????#│???├──?common???????????#│???├──?contrib??????????#│???├──?electron-browser?#│???├──?services?????????#│???└──?test?????????????#├──?css.build.js??#?用于插件構(gòu)建的CSS?loader├──?css.js????????#?CSS?loader├──?editor????????#?對(duì)接IDE?Core(讀取編輯/交互狀態(tài)),提供命令、上下文菜單、hover、snippet等支持├──?loader.js?????#?AMD?loader(用于異步加載AMD模塊)├──?nls.build.js??#?用于插件構(gòu)建的NLS?loader└──?nls.js????????#?NLS(National?Language?Support)多語言loader


核心層

  • base: 提供通用服務(wù)和構(gòu)建用戶界面

  • platform: 注入服務(wù)和基礎(chǔ)服務(wù)代碼

  • editor: 微軟 Monaco 編輯器,也可獨(dú)立運(yùn)行使用

  • wrokbench: 配合 Monaco 并且給 viewlets 提供框架:如:瀏覽器狀態(tài)欄,菜單欄利用 electron 實(shí)現(xiàn)桌面程序

核心環(huán)境

整個(gè)項(xiàng)目完全使用 typescript 實(shí)現(xiàn),electron 中運(yùn)行主進(jìn)程和渲染進(jìn)程,使用的 api 有所不同,所以在 core 中每個(gè)目錄組織也是按照使用的 api 來安排,
運(yùn)行的環(huán)境分為幾類:

  • common: 只使用 javascritp api 的代碼,能在任何環(huán)境下運(yùn)行

  • browser: 瀏覽器 api, 如操作 dom; 可以調(diào)用 common

  • node: 需要使用 node 的 api,比如文件 io 操作

  • electron-brower: 渲染進(jìn)程 api, 可以調(diào)用 common, brower, node, 依賴electron renderer-process API

  • electron-main: 主進(jìn)程 api, 可以調(diào)用: common, node 依賴于electron main-process AP


3.啟動(dòng)主進(jìn)程

Electron 通過 package.json 中的 main 字段來定義應(yīng)用入口。

main.js 是 vscode 的入口。

  • src/main.js
    _ vs/code/electron-main/main.ts
    _ vs/code/electron-main/app.ts
    _ vs/code/electron-main/windows.ts
    _ vs/workbench/electron-browser/desktop.main.ts * vs/workbench/browser/workbench.ts

app.once('ready',?function?()?{//啟動(dòng)追蹤,后面會(huì)講到,跟性能檢測(cè)優(yōu)化相關(guān)。if?(args['trace'])?{//?@ts-ignoreconst?contentTracing?=?require('electron').contentTracing;const?traceOptions?=?{categoryFilter:?args['trace-category-filter']?||?'*',traceOptions:?args['trace-options']?||?'record-until-full,enable-sampling'};contentTracing.startRecording(traceOptions,?()?=>?onReady());}?else?{onReady();} }); function?onReady()?{perf.mark('main:appReady');Promise.all([nodeCachedDataDir.ensureExists(),?userDefinedLocale]).then(([cachedDataDir,?locale])?=>?{//1.?這里嘗試獲取本地配置信息,如果有的話會(huì)傳遞到startupif?(locale?&&?!nlsConfiguration)?{nlsConfiguration?=?lp.getNLSConfiguration(product.commit,?userDataPath,?metaDataFile,?locale);}if?(!nlsConfiguration)?{nlsConfiguration?=?Promise.resolve(undefined);}nlsConfiguration.then(nlsConfig?=>?{//4.?首先會(huì)檢查用戶語言環(huán)境配置,如果沒有設(shè)置默認(rèn)使用英語const?startup?=?nlsConfig?=>?{nlsConfig._languagePackSupport?=?true;process.env['VSCODE_NLS_CONFIG']?=?JSON.stringify(nlsConfig);process.env['VSCODE_NODE_CACHED_DATA_DIR']?=?cachedDataDir?||?'';perf.mark('willLoadMainBundle');//使用微軟的loader組件加載electron-main/main文件require('./bootstrap-amd').load('vs/code/electron-main/main',?()?=>?{perf.mark('didLoadMainBundle');});};//?2.?接收到有效的配置傳入是其生效,調(diào)用startupif?(nlsConfig)?{startup(nlsConfig);}//?3.?這里嘗試使用本地的應(yīng)用程序//?應(yīng)用程序設(shè)置區(qū)域在ready事件后才有效else?{let?appLocale?=?app.getLocale();if?(!appLocale)?{startup({?locale:?'en',?availableLanguages:?{}?});}?else?{//?配置兼容大小寫敏感,所以統(tǒng)一轉(zhuǎn)換成小寫appLocale?=?appLocale.toLowerCase();//?這里就會(huì)調(diào)用config服務(wù),把本地配置加載進(jìn)來再調(diào)用startuplp.getNLSConfiguration(product.commit,?userDataPath,?metaDataFile,?appLocale).then(nlsConfig?=>?{if?(!nlsConfig)?{nlsConfig?=?{?locale:?appLocale,?availableLanguages:?{}?};}startup(nlsConfig);});}}});},?console.error); }

vs/code/electron-main/main.ts

electron-main/main 是程序真正啟動(dòng)的入口,進(jìn)入 main process 初始化流程.

這里主要做了兩件事情:

  • 初始化 Service

  • 啟動(dòng)主實(shí)例

  • 直接看 startup 方法的實(shí)現(xiàn),基礎(chǔ)服務(wù)初始化完成后會(huì)加載 CodeApplication, mainIpcServer, instanceEnvironment,調(diào)用 startup 方法啟動(dòng) APP

    private?async?startup(args:?ParsedArgs):?Promise<void>?{//spdlog?日志服務(wù)const?bufferLogService?=?new?BufferLogService();//?1.?調(diào)用?createServicesconst?[instantiationService,?instanceEnvironment]?=?this.createServices(args,?bufferLogService);try?{//?1.1?初始化Service服務(wù)await?instantiationService.invokeFunction(async?accessor?=>?{//?基礎(chǔ)服務(wù),包括一些用戶數(shù)據(jù),緩存目錄const?environmentService?=?accessor.get(IEnvironmentService);//?配置服務(wù)const?configurationService?=?accessor.get(IConfigurationService);//?持久化數(shù)據(jù)const?stateService?=?accessor.get(IStateService);try?{await?this.initServices(environmentService,?configurationService?as?ConfigurationService,?stateService?as?StateService);}?catch?(error)?{//?拋出錯(cuò)誤對(duì)話框this.handleStartupDataDirError(environmentService,?error);throw?error;}});//?1.2?啟動(dòng)實(shí)例await?instantiationService.invokeFunction(async?accessor?=>?{const?environmentService?=?accessor.get(IEnvironmentService);const?logService?=?accessor.get(ILogService);const?lifecycleService?=?accessor.get(ILifecycleService);const?configurationService?=?accessor.get(IConfigurationService);const?mainIpcServer?=?await?this.doStartup(logService,?environmentService,?lifecycleService,?instantiationService,?true);bufferLogService.logger?=?new?SpdLogService('main',?environmentService.logsPath,?bufferLogService.getLevel());once(lifecycleService.onWillShutdown)(()?=>?(configurationService?as?ConfigurationService).dispose());return?instantiationService.createInstance(CodeApplication,?mainIpcServer,?instanceEnvironment).startup();});}?catch?(error)?{instantiationService.invokeFunction(this.quit,?error);}}


    Service

    這里通過 createService 創(chuàng)建一些基礎(chǔ)的 Service

    運(yùn)行環(huán)境服務(wù) EnvironmentService

    src/vs/platform/environment/node/environmentService.ts

    通過這個(gè)服務(wù)獲取當(dāng)前啟動(dòng)目錄,日志目錄,操作系統(tǒng)信息,配置文件目錄,用戶目錄等。

    日志服務(wù) MultiplexLogService

    src/vs/platform/log/common/log.ts

    默認(rèn)使用控制臺(tái)日志 ConsoleLogMainService
    其中包含性能追蹤和釋放信息,日志輸出級(jí)別

    配置服務(wù) ConfigurationService

    src/vs/platform/configuration/node/configurationService.ts

    從運(yùn)行環(huán)境服務(wù)獲取內(nèi)容

    生命周期服務(wù) LifecycleService

    src/vs/platform/lifecycle/common/lifecycleService.ts

    監(jiān)聽事件,electron app 模塊 比如:ready, window-all-closed,before-quit

    可以參考官方electron app 文檔

    狀態(tài)服務(wù) StateService

    src/vs/platform/state/node/stateService.ts

    通過 FileStorage 讀寫 storage.json 存儲(chǔ),里記錄一些與程序運(yùn)行狀態(tài)有關(guān)的鍵值對(duì)

    請(qǐng)求服務(wù) RequestService

    src/vs/platform/request/browser/requestService.ts

    這里使用的是原生 ajax 請(qǐng)求,實(shí)現(xiàn)了 request 方法

    主題服務(wù) ThemeMainService

    src/vs/platform/theme/electron-main/themeMainService.ts

    這里只設(shè)置背景顏色,通過 getBackgroundColor 方法 IStateService 存儲(chǔ)

    簽名服務(wù) SignService

    src/vs/platform/sign/node/signService.ts

    private?createServices(args:?ParsedArgs,?bufferLogService:?BufferLogService):?[IInstantiationService,?typeof?process.env]?{//服務(wù)注冊(cè)容器const?services?=?new?ServiceCollection();const?environmentService?=?new?EnvironmentService(args,?process.execPath);const?instanceEnvironment?=?this.patchEnvironment(environmentService);?//?Patch?`process.env`?with?the?instance's?environmentservices.set(IEnvironmentService,?environmentService);const?logService?=?new?MultiplexLogService([new?ConsoleLogMainService(getLogLevel(environmentService)),?bufferLogService]);process.once('exit',?()?=>?logService.dispose());//日志服務(wù)services.set(ILogService,?logService);//配置服務(wù)services.set(IConfigurationService,?new?ConfigurationService(environmentService.settingsResource));//生命周期services.set(ILifecycleService,?new?SyncDescriptor(LifecycleService));//狀態(tài)存儲(chǔ)services.set(IStateService,?new?SyncDescriptor(StateService));//網(wǎng)絡(luò)請(qǐng)求services.set(IRequestService,?new?SyncDescriptor(RequestService));//主題設(shè)定services.set(IThemeMainService,?new?SyncDescriptor(ThemeMainService));//簽名服務(wù)services.set(ISignService,?new?SyncDescriptor(SignService));return?[new?InstantiationService(services,?true),?instanceEnvironment]; }


    4.實(shí)例化服務(wù)

    SyncDescriptor 負(fù)責(zé)注冊(cè)這些服務(wù),當(dāng)用到該服務(wù)時(shí)進(jìn)程實(shí)例化使用

    src/vs/platform/instantiation/common/descriptors.ts

    export?class?SyncDescriptor<T>?{readonly?ctor:?any;readonly?staticArguments:?any[];readonly?supportsDelayedInstantiation:?boolean;constructor(ctor:?new?(...args:?any[])?=>?T,?staticArguments:?any[]?=?[],?supportsDelayedInstantiation:?boolean?=?false)?{this.ctor?=?ctor;this.staticArguments?=?staticArguments;this.supportsDelayedInstantiation?=?supportsDelayedInstantiation;} }

    main.ts 中 startup 方法調(diào)用 invokeFunction.get 實(shí)例化服務(wù)

    await?instantiationService.invokeFunction(async?accessor?=>?{const?environmentService?=?accessor.get(IEnvironmentService);const?configurationService?=?accessor.get(IConfigurationService);const?stateService?=?accessor.get(IStateService);try?{await?this.initServices(environmentService,?configurationService?as?ConfigurationService,?stateService?as?StateService);}?catch?(error)?{//?Show?a?dialog?for?errors?that?can?be?resolved?by?the?userthis.handleStartupDataDirError(environmentService,?error);throw?error;} });

    get 方法調(diào)用_getOrCreateServiceInstance,這里第一次創(chuàng)建會(huì)存入緩存中
    下次實(shí)例化對(duì)象時(shí)會(huì)優(yōu)先從緩存中獲取對(duì)象。

    src/vs/platform/instantiation/common/instantiationService.ts

    invokeFunction<R,?TS?extends?any[]?=?[]>(fn:?(accessor:?ServicesAccessor,?...args:?TS)?=>?R,?...args:?TS):?R?{let?_trace?=?Trace.traceInvocation(fn);let?_done?=?false;try?{const?accessor:?ServicesAccessor?=?{get:?<T>(id:?ServiceIdentifier<T>,?isOptional?:?typeof?optional)?=>?{if?(_done)?{throw?illegalState('service?accessor?is?only?valid?during?the?invocation?of?its?target?method');}const?result?=?this._getOrCreateServiceInstance(id,?_trace);if?(!result?&&?isOptional?!==?optional)?{throw?new?Error(`[invokeFunction]?unknown?service?'${id}'`);}return?result;}};return?fn.apply(undefined,?[accessor,?...args]);}?finally?{_done?=?true;_trace.stop();} } private?_getOrCreateServiceInstance<T>(id:?ServiceIdentifier<T>,?_trace:?Trace):?T?{let?thing?=?this._getServiceInstanceOrDescriptor(id);if?(thing?instanceof?SyncDescriptor)?{return?this._createAndCacheServiceInstance(id,?thing,?_trace.branch(id,?true));}?else?{_trace.branch(id,?false);return?thing;} }


    vs/code/electron-main/app.ts

    這里首先觸發(fā) CodeApplication.startup()方法, 在第一個(gè)窗口打開 3 秒后成為共享進(jìn)程,

    async?startup():?Promise<void>?{...//?1.?第一個(gè)窗口創(chuàng)建共享進(jìn)程const?sharedProcess?=?this.instantiationService.createInstance(SharedProcess,?machineId,?this.userEnv);const?sharedProcessClient?=?sharedProcess.whenReady().then(()?=>?connect(this.environmentService.sharedIPCHandle,?'main'));this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(()?=>?{this._register(new?RunOnceScheduler(async?()?=>?{const?userEnv?=?await?getShellEnvironment(this.logService,?this.environmentService);sharedProcess.spawn(userEnv);},?3000)).schedule();});//?2.?創(chuàng)建app實(shí)例const?appInstantiationService?=?await?this.createServices(machineId,?trueMachineId,?sharedProcess,?sharedProcessClient);//?3.?打開一個(gè)窗口?調(diào)用const?windows?=?appInstantiationService.invokeFunction(accessor?=>?this.openFirstWindow(accessor,?electronIpcServer,?sharedProcessClient));//?4.?窗口打開后執(zhí)行生命周期和授權(quán)操作this.afterWindowOpen();...//vscode結(jié)束了性能問題的追蹤if?(this.environmentService.args.trace)?{this.stopTracingEventually(windows);} }

    openFirstWindow 主要實(shí)現(xiàn)
    CodeApplication.openFirstWindow 首次開啟窗口時(shí),創(chuàng)建 Electron 的 IPC,使主進(jìn)程和渲染進(jìn)程間通信。

    window 會(huì)被注冊(cè)到 sharedProcessClient,主進(jìn)程和共享進(jìn)程通信
    根據(jù) environmentService 提供的參數(shù)(path,uri)調(diào)用 windowsMainService.open 方法打開窗口

    private?openFirstWindow(accessor:?ServicesAccessor,?electronIpcServer:?ElectronIPCServer,?sharedProcessClient:?Promise<Client<string>>):?ICodeWindow[]?{...//?1.?注入Electron?IPC?Service,?windows窗口管理,菜單欄等服務(wù)//?2.?根據(jù)environmentService進(jìn)行參數(shù)配置const?macOpenFiles:?string[]?=?(<any>global).macOpenFiles;const?context?=?!!process.env['VSCODE_CLI']???OpenContext.CLI?:?OpenContext.DESKTOP;const?hasCliArgs?=?hasArgs(args._);const?hasFolderURIs?=?hasArgs(args['folder-uri']);const?hasFileURIs?=?hasArgs(args['file-uri']);const?noRecentEntry?=?args['skip-add-to-recently-opened']?===?true;const?waitMarkerFileURI?=?args.wait?&&?args.waitMarkerFilePath???URI.file(args.waitMarkerFilePath)?:?undefined;...//?打開主窗口,默認(rèn)從執(zhí)行命令行中讀取參數(shù)return?windowsMainService.open({context,cli:?args,forceNewWindow:?args['new-window']?||?(!hasCliArgs?&&?args['unity-launch']),diffMode:?args.diff,noRecentEntry,waitMarkerFileURI,gotoLineMode:?args.goto,initialStartup:?true});}

    vs/code/electron-main/windows.ts

    接下來到了 electron 的 windows 窗口,open 方法在 doOpen 中執(zhí)行窗口配置初始化,最終調(diào)用 openInBrowserWindow -> 執(zhí)行 doOpenInBrowserWindow 是其打開 window,主要步驟如下:

    private?openInBrowserWindow(options:?IOpenBrowserWindowOptions):?ICodeWindow?{...//?New?windowif?(!window)?{//1.判斷是否全屏創(chuàng)建窗口...//?2.?創(chuàng)建實(shí)例窗口window?=?this.instantiationService.createInstance(CodeWindow,?{state,extensionDevelopmentPath:?configuration.extensionDevelopmentPath,isExtensionTestHost:?!!configuration.extensionTestsPath});//?3.添加到當(dāng)前窗口控制器WindowsManager.WINDOWS.push(window);//?4.窗口監(jiān)聽器window.win.webContents.removeAllListeners('devtools-reload-page');?//?remove?built?in?listener?so?we?can?handle?this?on?our?ownwindow.win.webContents.on('devtools-reload-page',?()?=>?this.reload(window!));window.win.webContents.on('crashed',?()?=>?this.onWindowError(window!,?WindowError.CRASHED));window.win.on('unresponsive',?()?=>?this.onWindowError(window!,?WindowError.UNRESPONSIVE));window.win.on('closed',?()?=>?this.onWindowClosed(window!));//?5.注冊(cè)窗口生命周期(this.lifecycleService?as?LifecycleService).registerWindow(window);}...return?window; }

    doOpenInBrowserWindow 會(huì)調(diào)用 window.load 方法 在 window.ts 中實(shí)現(xiàn)

    load(config:?IWindowConfiguration,?isReload?:?boolean,?disableExtensions?:?boolean):?void?{...//?Load?URLperf.mark('main:loadWindow');this._win.loadURL(this.getUrl(configuration));... }private?getUrl(windowConfiguration:?IWindowConfiguration):?string?{...//加載歡迎屏幕的htmllet?configUrl?=?this.doGetUrl(config);...return?configUrl; }//默認(rèn)加載?vs/code/electron-browser/workbench/workbench.html private?doGetUrl(config:?object):?string?{return?`${require.toUrl('vs/code/electron-browser/workbench/workbench.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; }

    main process 的使命完成, 主界面進(jìn)行構(gòu)建布局。

    在 workbench.html 中加載了 workbench.js,
    這里調(diào)用 return require('vs/workbench/electron-browser/desktop.main').main(configuration);實(shí)現(xiàn)對(duì)主界面的展示

    vs/workbench/electron-browser/desktop.main.ts

    創(chuàng)建工作區(qū),調(diào)用 workbench.startup()方法,構(gòu)建主界面展示布局

    ... async?open():?Promise<void>?{const?services?=?await?this.initServices();await?domContentLoaded();mark('willStartWorkbench');//?1.創(chuàng)建工作區(qū)const?workbench?=?new?Workbench(document.body,?services.serviceCollection,?services.logService);//?2.監(jiān)聽窗口變化this._register(addDisposableListener(window,?EventType.RESIZE,?e?=>?this.onWindowResize(e,?true,?workbench)));//?3.工作臺(tái)生命周期this._register(workbench.onShutdown(()?=>?this.dispose()));this._register(workbench.onWillShutdown(event?=>?event.join(services.storageService.close())));//?3.啟動(dòng)工作區(qū)const?instantiationService?=?workbench.startup();... } ...

    vs/workbench/browser/workbench.ts

    工作區(qū)繼承自 layout 類,主要作用是構(gòu)建工作區(qū),創(chuàng)建界面布局。

    export?class?Workbench?extends?Layout?{...startup():?IInstantiationService?{try?{...//?Servicesconst?instantiationService?=?this.initServices(this.serviceCollection);instantiationService.invokeFunction(async?accessor?=>?{const?lifecycleService?=?accessor.get(ILifecycleService);const?storageService?=?accessor.get(IStorageService);const?configurationService?=?accessor.get(IConfigurationService);//?Layoutthis.initLayout(accessor);//?Registriesthis.startRegistries(accessor);//?Context?Keysthis._register(instantiationService.createInstance(WorkbenchContextKeysHandler));//?注冊(cè)監(jiān)聽事件this.registerListeners(lifecycleService,?storageService,?configurationService);//?渲染工作區(qū)this.renderWorkbench(instantiationService,?accessor.get(INotificationService)?as?NotificationService,?storageService,?configurationService);//?創(chuàng)建工作區(qū)布局this.createWorkbenchLayout(instantiationService);//?布局構(gòu)建this.layout();//?Restoretry?{await?this.restoreWorkbench(accessor.get(IEditorService),?accessor.get(IEditorGroupsService),?accessor.get(IViewletService),?accessor.get(IPanelService),?accessor.get(ILogService),?lifecycleService);}?catch?(error)?{onUnexpectedError(error);}});return?instantiationService;}?catch?(error)?{onUnexpectedError(error);throw?error;?//?rethrow?because?this?is?a?critical?issue?we?cannot?handle?properly?here}}... }


    5.事件分發(fā)

    event

    src/vs/base/common/event.ts

    程序中常見使用 once 方法進(jìn)行事件綁定, 給定一個(gè)事件,返回一個(gè)只觸發(fā)一次的事件,放在匿名函數(shù)返回

    export?function?once<T>(event:?Event<T>):?Event<T>?{return?(listener,?thisArgs?=?null,?disposables?)?=>?{//?設(shè)置次變量,防止事件重復(fù)觸發(fā)造成事件污染let?didFire?=?false;let?result:?IDisposable;result?=?event(e?=>?{if?(didFire)?{return;}?else?if?(result)?{result.dispose();}?else?{didFire?=?true;}return?listener.call(thisArgs,?e);},?null,?disposables);if?(didFire)?{result.dispose();}return?result;}; }

    循環(huán)派發(fā)了所有注冊(cè)的事件, 事件會(huì)存儲(chǔ)到一個(gè)事件隊(duì)列,通過 fire 方法觸發(fā)事件

    private _deliveryQueue?: LinkedList<[Listener, T]>;//事件存儲(chǔ)隊(duì)列

    fire(event:?T):?void?{if?(this._listeners)?{//?將所有事件傳入?delivery?queue//?內(nèi)部/嵌套方式通過emit發(fā)出.//?this調(diào)用事件驅(qū)動(dòng)if?(!this._deliveryQueue)?{this._deliveryQueue?=?new?LinkedList();}for?(let?iter?=?this._listeners.iterator(),?e?=?iter.next();?!e.done;?e?=?iter.next())?{this._deliveryQueue.push([e.value,?event]);}while?(this._deliveryQueue.size?>?0)?{const?[listener,?event]?=?this._deliveryQueue.shift()!;try?{if?(typeof?listener?===?'function')?{listener.call(undefined,?event);}?else?{listener[0].call(listener[1],?event);}}?catch?(e)?{onUnexpectedError(e);}}} }


    6.進(jìn)程通信

    主進(jìn)程

    src/vs/code/electron-main/main.ts

    main.ts 在啟動(dòng)應(yīng)用后就創(chuàng)建了一個(gè)主進(jìn)程 main process,它可以通過 electron 中的一些模塊直接與原生 GUI 交互。

    server?=?await?serve(environmentService.mainIPCHandle); once(lifecycleService.onWillShutdown)(()?=>?server.dispose());

    渲染進(jìn)程

    僅啟動(dòng)主進(jìn)程并不能給你的應(yīng)用創(chuàng)建應(yīng)用窗口。窗口是通過 main 文件里的主進(jìn)程調(diào)用叫 BrowserWindow 的模塊創(chuàng)建的。

    主進(jìn)程與渲染進(jìn)程之間的通信

    在 electron 中,主進(jìn)程與渲染進(jìn)程有很多通信的方法。比如 ipcRenderer 和 ipcMain,還可以在渲染進(jìn)程使用 remote 模塊。

    ipcMain & ipcRenderer

    • 主進(jìn)程:ipcMain

    • 渲染進(jìn)程:ipcRenderer

    ipcMain 模塊和 ipcRenderer 是類 EventEmitter 的實(shí)例。

    在主進(jìn)程中使用 ipcMain 接收渲染線程發(fā)送過來的異步或同步消息,發(fā)送過來的消息將觸發(fā)事件。

    在渲染進(jìn)程中使用 ipcRenderer 向主進(jìn)程發(fā)送同步或異步消息,也可以接收到主進(jìn)程的消息。

    • 發(fā)送消息,事件名為 channel .

    • 回應(yīng)同步消息, 你可以設(shè)置 event.returnValue .

    • 回應(yīng)異步消息, 你可以使用 event.sender.send(…)

    創(chuàng)建 IPC 服務(wù)
    src/vs/base/parts/ipc/node/ipc.net.ts

    這里返回一個(gè) promise 對(duì)象,成功則 createServer

    export?function?serve(hook:?any):?Promise<Server>?{return?new?Promise<Server>((c,?e)?=>?{const?server?=?createServer();server.on('error',?e);server.listen(hook,?()?=>?{server.removeListener('error',?e);c(new?Server(server));});}); }

    創(chuàng)建信道

    src/vs/code/electron-main/app.ts

    • mainIpcServer * launchChannel

    • electronIpcServer
      _ updateChannel
      _ issueChannel
      _ workspacesChannel
      _ windowsChannel
      _ menubarChannel
      _ urlChannel
      _ storageChannel
      _ logLevelChannel

    private?openFirstWindow(accessor:?ServicesAccessor,?electronIpcServer:?ElectronIPCServer,?sharedProcessClient:?Promise<Client<string>>):?ICodeWindow[]?{//?Register?more?Main?IPC?servicesconst?launchService?=?accessor.get(ILaunchService);const?launchChannel?=?new?LaunchChannel(launchService);this.mainIpcServer.registerChannel('launch',?launchChannel);//?Register?more?Electron?IPC?servicesconst?updateService?=?accessor.get(IUpdateService);const?updateChannel?=?new?UpdateChannel(updateService);electronIpcServer.registerChannel('update',?updateChannel);const?issueService?=?accessor.get(IIssueService);const?issueChannel?=?new?IssueChannel(issueService);electronIpcServer.registerChannel('issue',?issueChannel);const?workspacesService?=?accessor.get(IWorkspacesMainService);const?workspacesChannel?=?new?WorkspacesChannel(workspacesService);electronIpcServer.registerChannel('workspaces',?workspacesChannel);const?windowsService?=?accessor.get(IWindowsService);const?windowsChannel?=?new?WindowsChannel(windowsService);electronIpcServer.registerChannel('windows',?windowsChannel);sharedProcessClient.then(client?=>?client.registerChannel('windows',?windowsChannel));const?menubarService?=?accessor.get(IMenubarService);const?menubarChannel?=?new?MenubarChannel(menubarService);electronIpcServer.registerChannel('menubar',?menubarChannel);const?urlService?=?accessor.get(IURLService);const?urlChannel?=?new?URLServiceChannel(urlService);electronIpcServer.registerChannel('url',?urlChannel);const?storageMainService?=?accessor.get(IStorageMainService);const?storageChannel?=?this._register(new?GlobalStorageDatabaseChannel(this.logService,?storageMainService));electronIpcServer.registerChannel('storage',?storageChannel);//?Log?level?managementconst?logLevelChannel?=?new?LogLevelSetterChannel(accessor.get(ILogService));electronIpcServer.registerChannel('loglevel',?logLevelChannel);sharedProcessClient.then(client?=>?client.registerChannel('loglevel',?logLevelChannel));...//?default:?read?paths?from?clireturn?windowsMainService.open({context,cli:?args,forceNewWindow:?args['new-window']?||?(!hasCliArgs?&&?args['unity-launch']),diffMode:?args.diff,noRecentEntry,waitMarkerFileURI,gotoLineMode:?args.goto,initialStartup:?true});}

    每一個(gè)信道,內(nèi)部實(shí)現(xiàn)兩個(gè)方法 listen 和 call

    例如:src/vs/platform/localizations/node/localizationsIpc.ts

    構(gòu)造函數(shù)綁定事件

    export?class?LocalizationsChannel?implements?IServerChannel?{onDidLanguagesChange:?Event<void>;constructor(private?service:?ILocalizationsService)?{this.onDidLanguagesChange?=?Event.buffer(service.onDidLanguagesChange,?true);}listen(_:?unknown,?event:?string):?Event<any>?{switch?(event)?{case?'onDidLanguagesChange':?return?this.onDidLanguagesChange;}throw?new?Error(`Event?not?found:?${event}`);}call(_:?unknown,?command:?string,?arg?:?any):?Promise<any>?{switch?(command)?{case?'getLanguageIds':?return?this.service.getLanguageIds(arg);}throw?new?Error(`Call?not?found:?${command}`);} }


    7.主要窗口

    workbench.ts 中 startup 里面 Workbench 負(fù)責(zé)創(chuàng)建主界面
    src/vs/workbench/browser/workbench.ts

    startup():?IInstantiationService?{try?{...instantiationService.invokeFunction(async?accessor?=>?{//?渲染主工作界面this.renderWorkbench(instantiationService,?accessor.get(INotificationService)?as?NotificationService,?storageService,?configurationService);//?界面布局this.createWorkbenchLayout(instantiationService);//?Layoutthis.layout();//?Restoretry?{await?this.restoreWorkbench(accessor.get(IEditorService),?accessor.get(IEditorGroupsService),?accessor.get(IViewletService),?accessor.get(IPanelService),?accessor.get(ILogService),?lifecycleService);}?catch?(error)?{onUnexpectedError(error);}});return?instantiationService;}?catch?(error)?{onUnexpectedError(error);throw?error;?//?rethrow?because?this?is?a?critical?issue?we?cannot?handle?properly?here} }

    渲染主工作臺(tái),渲染完之后加入到 container 中,container 加入到 parent, parent 就是 body 了。

    this.parent.appendChild(this.container);

    private?renderWorkbench(instantiationService:?IInstantiationService,?notificationService:?NotificationService,?storageService:?IStorageService,?configurationService:?IConfigurationService):?void?{...//TITLEBAR_PART?頂部操作欄//ACTIVITYBAR_PART?最左側(cè)菜單選項(xiàng)卡//SIDEBAR_PART?左側(cè)邊欄,顯示文件,結(jié)果展示等//EDITOR_PART?右側(cè)窗口,代碼編寫,歡迎界面等//STATUSBAR_PART?底部狀態(tài)欄[{?id:?Parts.TITLEBAR_PART,?role:?'contentinfo',?classes:?['titlebar']?},{?id:?Parts.ACTIVITYBAR_PART,?role:?'navigation',?classes:?['activitybar',?this.state.sideBar.position?===?Position.LEFT???'left'?:?'right']?},{?id:?Parts.SIDEBAR_PART,?role:?'complementary',?classes:?['sidebar',?this.state.sideBar.position?===?Position.LEFT???'left'?:?'right']?},{?id:?Parts.EDITOR_PART,?role:?'main',?classes:?['editor'],?options:?{?restorePreviousState:?this.state.editor.restoreEditors?}?},{?id:?Parts.PANEL_PART,?role:?'complementary',?classes:?['panel',?this.state.panel.position?===?Position.BOTTOM???'bottom'?:?'right']?},{?id:?Parts.STATUSBAR_PART,?role:?'contentinfo',?classes:?['statusbar']?}].forEach(({?id,?role,?classes,?options?})?=>?{const?partContainer?=?this.createPart(id,?role,?classes);if?(!configurationService.getValue('workbench.useExperimentalGridLayout'))?{//?TODO@Ben?cleanup?once?moved?to?grid//?Insert?all?workbench?parts?at?the?beginning.?Issue?#52531//?This?is?primarily?for?the?title?bar?to?allow?overriding?-webkit-app-regionthis.container.insertBefore(partContainer,?this.container.lastChild);}this.getPart(id).create(partContainer,?options);});//?將工作臺(tái)添加至container?dom渲染this.parent.appendChild(this.container);}

    workbench 最后調(diào)用 this.layout()方法,將窗口占據(jù)整個(gè)界面,渲染完成

    layout(options?:?ILayoutOptions):?void?{if?(!this.disposed)?{this._dimension?=?getClientArea(this.parent);if?(this.workbenchGrid?instanceof?Grid)?{position(this.container,?0,?0,?0,?0,?'relative');size(this.container,?this._dimension.width,?this._dimension.height);//?Layout?the?grid?widgetthis.workbenchGrid.layout(this._dimension.width,?this._dimension.height);}?else?{this.workbenchGrid.layout(options);}//?Emit?as?eventthis._onLayout.fire(this._dimension);}}


    8.開發(fā)調(diào)試

    app.once('ready',?function?()?{//啟動(dòng)追蹤if?(args['trace'])?{//?@ts-ignoreconst?contentTracing?=?require('electron').contentTracing;const?traceOptions?=?{categoryFilter:?args['trace-category-filter']?||?'*',traceOptions:?args['trace-options']?||?'record-until-full,enable-sampling'};contentTracing.startRecording(traceOptions,?()?=>?onReady());}?else?{onReady();} });


    啟動(dòng)追蹤

    這里如果傳入 trace 參數(shù),在 onReady 啟動(dòng)之前會(huì)調(diào)用 chromium 的收集跟蹤數(shù)據(jù),
    提供的底層的追蹤工具允許我們深度了解 V8 的解析以及其他時(shí)間消耗情況,

    一旦收到可以開始記錄的請(qǐng)求,記錄將會(huì)立馬啟動(dòng)并且在子進(jìn)程是異步記錄聽的. 當(dāng)所有的子進(jìn)程都收到 startRecording 請(qǐng)求的時(shí)候,callback 將會(huì)被調(diào)用.

    categoryFilter 是一個(gè)過濾器,它用來控制那些分類組應(yīng)該被用來查找.過濾器應(yīng)當(dāng)有一個(gè)可選的 - 前綴來排除匹配的分類組.不允許同一個(gè)列表既是包含又是排斥.

    contentTracing.startRecording(options, callback)

    • options Object
      _ categoryFilter String
      _ traceOptions String

    • callback Function

    關(guān)于 trace 的詳細(xì)介紹

    結(jié)束追蹤

    contentTracing.stopRecording(resultFilePath, callback)

    • resultFilePath String

    • callback Function
      在成功啟動(dòng)窗口后,程序結(jié)束性能追蹤,停止對(duì)所有子進(jìn)程的記錄.

    子進(jìn)程通常緩存查找數(shù)據(jù),并且僅僅將數(shù)據(jù)截取和發(fā)送給主進(jìn)程.這有利于在通過 IPC 發(fā)送查找數(shù)據(jù)之前減小查找時(shí)的運(yùn)行開銷,這樣做很有價(jià)值.因此,發(fā)送查找數(shù)據(jù),我們應(yīng)當(dāng)異步通知所有子進(jìn)程來截取任何待查找的數(shù)據(jù).

    一旦所有子進(jìn)程接收到了 stopRecording 請(qǐng)求,將調(diào)用 callback ,并且返回一個(gè)包含查找數(shù)據(jù)的文件.

    如果 resultFilePath 不為空,那么將把查找數(shù)據(jù)寫入其中,否則寫入一個(gè)臨時(shí)文件.實(shí)際文件路徑如果不為空,則將調(diào)用 callback .

    debug

    調(diào)試界面在菜單欄找到 Help->Toggle Developers Tools

    調(diào)出 Chrome 開發(fā)者調(diào)試工具進(jìn)行調(diào)試


    參考

    https://electronjs.org/docs

    https://github.com/microsoft/vscode/wiki/How-to-Contribute

    https://github.com/Microsoft/vscode/wiki/Code-Organization

    http://xzper.com/2016/04/17/vscode%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%90/

    http://www.ayqy.net/blog/vs-code%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90/

    推薦閱讀:

    下一代 TGW 從13Mpps到50Mpps性能優(yōu)化之旅

    寫給前端工程師的 Flutter 詳細(xì)教程

    現(xiàn)代化 C++ 開發(fā)工具 CLion 從入門到精通

    總結(jié)

    以上是生活随笔為你收集整理的微软 VSCode IDE 源码分析揭秘的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    久久爱992xxoo | 久久久在线免费观看 | 日韩视频1 | 最近中文字幕视频网 | 久草电影免费在线观看 | 99久久精品久久久久久动态片 | 中文字幕av网站 | 久久亚洲精品国产亚洲老地址 | 久久理论片 | 日韩av电影手机在线观看 | 日韩美女av在线 | 国产婷婷一区二区 | 亚洲精品网站 | 久草免费手机视频 | 久久久久久久久亚洲精品 | 亚洲第二色 | 九九电影在线 | 韩日电影在线观看 | 日韩免费电影一区二区三区 | 欧美色图p | www.五月天激情 | 在线免费91| 91九色视频国产 | 国产中文字幕久久 | 99在线精品免费视频九九视 | 91cn国产在线 | 在线免费观看视频一区二区三区 | 精品国内自产拍在线观看视频 | 久久不射电影网 | 91在线区 | 白丝av在线 | 黄色av播放 | 99久久婷婷国产精品综合 | 欧美一区二区伦理片 | 91在线91| 日韩在线视频国产 | 99视频免费播放 | 中字幕视频在线永久在线观看免费 | 天天插综合 | 国产精品18久久久久久久久久久久 | 亚洲欧美国产精品 | 久久久久国产精品免费网站 | 91激情在线视频 | 一级黄色在线视频 | 狠狠色伊人亚洲综合网站野外 | 欧美a影视| 久二影院 | 国产午夜影院 | 国产麻豆果冻传媒在线观看 | 久久的色 | 六月婷婷久香在线视频 | 中文字幕一区二区三区久久 | 美女视频一区二区 | 国产 字幕 制服 中文 在线 | 91精品国产成人 | 嫩草av影院 | 国产精品久久久区三区天天噜 | 97超碰人人模人人人爽人人爱 | 国产原创av片 | 日本婷婷色 | 欧美一级日韩三级 | 亚洲第一成网站 | 99精品在线免费在线观看 | 国产成人精品亚洲日本在线观看 | 青青河边草观看完整版高清 | 日本一区二区免费在线观看 | 天天操夜夜想 | 久久综合色一综合色88 | 久久视频精品 | 探花视频免费观看高清视频 | 欧美日韩在线视频一区 | 欧美视频日韩 | 色婷丁香 | 蜜桃麻豆www久久囤产精品 | 亚州精品成人 | 麻豆小视频在线观看 | 精品国产免费一区二区三区五区 | 亚洲一级电影视频 | 国内精品久久天天躁人人爽 | 中文字幕一区二 | 久草视频在线资源 | 久久香蕉电影 | 97超碰人人澡人人爱 | 六月丁香六月婷婷 | 亚洲久在线 | 丁香电影小说免费视频观看 | 999久久久欧美日韩黑人 | 成 人 黄 色视频免费播放 | 在线中文字幕一区二区 | 少妇性bbb搡bbb爽爽爽欧美 | 五月天久久综合网 | 日韩av免费一区 | 欧美激情综合五月 | 欧美做受高潮电影o | 中文字幕一区二区三区在线视频 | 亚洲午夜久久久久久久久电影网 | 丁香婷婷久久久综合精品国产 | 国产在线更新 | 亚洲 中文 欧美 日韩vr 在线 | 一区二区视频电影在线观看 | 日韩肉感妇bbwbbwbbw | av一区二区在线观看中文字幕 | 91亚洲夫妻 | 夜夜躁狠狠躁日日躁 | a在线免费观看视频 | 国产麻豆果冻传媒在线观看 | 亚洲精品久久久久999中文字幕 | 成人黄大片视频在线观看 | 丁香激情综合久久伊人久久 | av电影在线不卡 | 香蕉视频色 | 人人草天天草 | 亚洲天天摸日日摸天天欢 | 欧美午夜a | 久久理论影院 | 亚洲免费av在线 | 久久99网站 | 青青久视频 | 久久久福利视频 | 99久久精品国产一区 | 91资源在线播放 | 91精品日韩 | 97在线观视频免费观看 | 视频91| 成人国产精品免费观看 | 91精品国产入口 | 中文字幕乱视频 | 久久久久女教师免费一区 | 激情综合色综合久久综合 | 欧美老少交 | 成人免费亚洲 | 在线观看免费av网 | 九九免费精品视频在线观看 | 色综合久久久久 | 亚洲理论视频 | 中文字幕在线乱 | 免费看精品久久片 | 国产精品99久久免费观看 | 久久视频在线观看中文字幕 | 久久久久久高潮国产精品视 | 精品国产亚洲日本 | 色六月婷婷| 夜夜夜夜操 | 亚洲免费在线观看视频 | 在线观看国产日韩 | 久久歪歪| 成人a视频片观看免费 | 在线免费91| 91 在线视频播放 | 中文字幕乱偷在线 | 99久久99视频只有精品 | 草久久影院 | 国产在线观看av | 久草久草在线观看 | 久久精品视频网站 | 国产成人精品av在线观 | 99re8这里有精品热视频免费 | 中文av影院 | 又黄又爽的免费高潮视频 | 欧美乱熟臀69xxxxxx | 国产精品久久精品 | 中文字幕日韩国产 | 99视频在线观看免费 | 精品在线亚洲视频 | 永久免费观看视频 | 国产一区二区免费 | www.69xx | 国产亚洲精品久久久久久无几年桃 | 午夜美女网站 | 国产99久久久精品视频 | 深夜成人av| 麻豆成人在线观看 | 欧美看片 | 五月色综合 | 国产精品久久久久久久久免费看 | 国产九色在线播放九色 | 成人网色| 亚洲国产精品99久久久久久久久 | 日韩三级在线观看 | 欧美黄色免费 | 国产在线91精品 | 国产高清不卡在线 | 久久午夜影视 | 久久99日韩 | 六月婷色 | 综合网中文字幕 | 久 久久影院 | 四虎在线免费观看视频 | 国产精品久久久久久久久婷婷 | 日韩av进入 | 人人舔人人干 | 91成人国产 | 成人免费xyz网站 | 国产精品激情偷乱一区二区∴ | 国产专区视频在线观看 | 国产成在线观看免费视频 | 91视频91自拍| 精品96久久久久久中文字幕无 | 区一区二区三区中文字幕 | 日韩精品一区二区三区免费视频观看 | 日韩中文在线播放 | 97精品国产一二三产区 | 国产精品无av码在线观看 | 在线观看aaa | 高清av免费一区中文字幕 | 久久成人精品视频 | 欧美婷婷综合 | 一区电影 | 91片黄在线观| 六月天色婷婷 | 夜夜操天天干, | 婷婷综合五月天 | 人人添人人 | 久久黄色小说 | 天天操综| 国产精品毛片久久久久久 | 精品久久一区二区三区 | 久久99爱视频 | 免费在线观看午夜视频 | 在线观看韩国av | 久久久国产精品一区二区三区 | 不卡的av在线播放 | 国产精品18久久久久久不卡孕妇 | 伊人婷婷| 免费日韩一区二区三区 | 91欧美视频网站 | 91黄色成人 | 久久精品精品电影网 | 五月天.com | 中文字幕一区二区三区在线观看 | 色婷婷成人网 | 亚洲精品三级 | 亚洲成人精品影院 | 欧美日韩精品影院 | 久草在线免费新视频 | 亚洲欧美视频网站 | 四虎国产精品成人免费影视 | 婷婷五天天在线视频 | 久久久久久久久久网 | 欧美一区二区精品在线 | 99r在线视频 | 婷婷色在线观看 | 97成人免费 | 成人免费观看在线视频 | 国产黄色精品在线观看 | 国产精品久久久久久a | 久久精品看片 | 99综合电影在线视频 | 免费观看的黄色片 | 三级a毛片| 久久国产亚洲视频 | 欧美日韩在线视频免费 | 午夜免费视频网站 | 欧美成年网站 | 亚洲天堂va| 欧美日本日韩aⅴ在线视频 插插插色综合 | 亚洲精品乱码久久久久久 | 一区久久久| 成年人国产精品 | av电影久久 | 奇米777777 | 91精品黄色 | 欧美大片大全 | 三级av中文字幕 | 国产999视频 | 欧美精品免费在线观看 | 一区二区中文字幕在线观看 | 日韩成人av在线 | 人人看看人人 | 高清不卡毛片 | 国产精品成久久久久 | 五月激情久久 | 中文在线最新版天堂 | 国产精品乱码高清在线看 | 成+人+色综合 | 综合网成人 | 97在线视频观看 | 久久精品久久精品久久39 | 激情片av | 久久午夜精品 | 日韩免费在线视频观看 | 人人干网| 国产精品精品国产婷婷这里av | 精品夜夜嗨av一区二区三区 | av天天色 | 不卡的av电影在线观看 | 亚洲一级影院 | 97超碰中文字幕 | www.人人草 | 国产精品久久一卡二卡 | 国产vs久久 | 国产91对白在线播 | 狠狠艹夜夜干 | 久久99国产精品自在自在app | 在线你懂 | 国产美腿白丝袜足在线av | 午夜精品久久久久久久99 | 国产高清视频色在线www | 精品国模一区二区三区 | 1000部国产精品成人观看 | 综合激情久久 | 在线视频欧美精品 | 在线观看麻豆av | av福利在线导航 | 91 中文字幕 | 日韩成人黄色av | 日韩一二区在线观看 | 天天色影院 | 国产免费看 | 亚洲3级 | 一本色道久久综合亚洲二区三区 | 在线观看视频黄 | 亚洲精品视频偷拍 | 免费观看丰满少妇做爰 | 久久国产精品一区二区 | 国产精品久久久久久久久久了 | 国产精品久久99 | 99久久日韩精品免费热麻豆美女 | 日韩欧美电影 | 成人午夜精品福利免费 | 97在线免费观看 | 99re国产视频 | 婷婷久月| 人人舔人人干 | 久久视频免费看 | 精品主播网红福利资源观看 | 久草视频在线资源 | 美女免费黄视频网站 | 91av免费在线观看 | 特级西西444www大精品视频免费看 | 最新日韩中文字幕 | 欧美性高跟鞋xxxxhd | 免费看av在线 | 欧美日韩免费视频 | av一区二区在线观看中文字幕 | 毛片网站在线看 | 麻豆视频在线免费观看 | 欧美日本不卡高清 | 亚洲午夜精品久久久 | 久久综合欧美精品亚洲一区 | 黄色小说在线免费观看 | 亚洲激情精品 | 日本精品视频在线观看 | www.狠狠干 | 91av99| 亚洲人成精品久久久久 | 麻豆国产精品va在线观看不卡 | 欧美成人精品欧美一级乱黄 | 青青河边草手机免费 | 丁香花五月 | 91禁在线观看 | 美女网色 | 国产91精品在线播放 | 粉嫩av一区二区三区四区五区 | 久久免费激情视频 | 999视频在线播放 | 在线视频 国产 日韩 | 怡红院久久| 国产精品乱码一区二区视频 | 亚洲国产精品视频在线观看 | avwww在线 | 在线欧美日韩 | 激情综合五月网 | 中文字幕永久 | 日韩中文字幕一区 | 丁香网五月天 | 1区2区视频 | 国产69久久久欧美一级 | 激情综合电影网 | 丁香六月婷婷综合 | 一区二区三区三区在线 | 欧美夫妻生活视频 | 日韩av专区 | 亚洲视频第一页 | 一区二区三区中文字幕在线观看 | 国产精品不卡 | 中文在线a天堂 | 99婷婷狠狠成为人免费视频 | 亚洲1区在线 | 在线免费观看视频一区二区三区 | 狠狠做深爱婷婷综合一区 | 99精品国产一区二区 | 五月天色中色 | www.五月婷 | 国产精品理论片在线播放 | 懂色av懂色av粉嫩av分享吧 | 91视频91色| 月下香电影 | 又黄又爽又色无遮挡免费 | 欧美一级特黄aaaaaa大片在线观看 | 97香蕉久久国产在线观看 | 亚洲视频网站在线观看 | 亚洲自拍偷拍色图 | 国产一区二区手机在线观看 | 在线观看亚洲专区 | 国产成人精品一区二 | 成人av一区二区三区 | 91女子私密保健养生少妇 | 国产剧情亚洲 | 久久久久久国产精品999 | 经典三级一区 | 久久久久久久久久影院 | 亚州av网站| 欧美精品乱码久久久久久按摩 | 国产在线va | 在线观看亚洲免费视频 | 日韩在线观看一区二区 | 国产涩涩在线观看 | 欧美日韩亚洲精品在线 | 超级碰碰碰视频 | 91日韩在线专区 | 97在线观看免费高清完整版在线观看 | 国产精品激情偷乱一区二区∴ | 国产精品18毛片一区二区 | 五月婷婷香蕉 | 精品久久久久久电影 | 日韩在线免费视频观看 | 国产精品短视频 | 国产精品美女久久久久久久久久久 | 日本中文字幕观看 | 青青河边草免费观看 | 婷婷丁香久久五月婷婷 | 久久久国产影视 | 国产高清av免费在线观看 | 成人免费观看电影 | 日日操天天操狠狠操 | 国产黄色精品在线 | 久久影院午夜论 | 91亚洲精品视频 | 亚洲国产精彩中文乱码av | 久久伊人国产精品 | 亚洲日本韩国一区二区 | 国产精品女人久久久久久 | 久久久亚洲国产精品麻豆综合天堂 | 亚洲精选在线 | 99久久99久久精品国产片 | 色综合天天色 | 激情五月婷婷综合 | 人人爽人人爱 | 日日夜夜骑 | 久久视频在线视频 | 91精品在线免费观看 | 在线观看a视频 | 久久大视频 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 在线视频日韩一区 | 中文在线字幕观看电影 | 激情av在线播放 | 国产精品福利在线观看 | 久久九精品 | 国产婷婷在线观看 | 欧产日产国产69 | 狠狠gao| 国产一级免费观看 | 国产精品国产三级国产不产一地 | av福利在线| 国产福利一区二区在线 | 麻豆播放 | 日韩精品在线观看av | 亚洲黄色软件 | 玖玖在线精品 | 成人黄在线观看 | 欧美激情综合五月色丁香小说 | 婷婷激情影院 | 在线国产日本 | 超碰国产97 | 天天爱天天射天天干天天 | 国产一区欧美二区 | avav片 | 人人爱人人爽 | 日韩欧美一区视频 | 国产成人亚洲在线观看 | www黄色com| 久久免费美女视频 | 91成人短视频在线观看 | 免费精品在线观看 | 亚洲日本一区二区在线 | 天天激情站 | 91完整视频 | 国产亚洲成av人片在线观看桃 | 超碰成人免费电影 | 亚洲国产精久久久久久久 | 久久精品一区二区三区国产主播 | 黄色在线观看www | 国产艹b视频 | 麻豆91小视频 | 亚洲精品xx | 国产精品麻豆免费版 | 欧美精品一区在线发布 | 午夜a区 | 精品人人人 | 狠狠色丁香久久婷婷综合丁香 | 国产精品www | 在线观看免费高清视频大全追剧 | 99精品国产99久久久久久97 | 91激情视频在线观看 | 2019av在线视频 | 九九免费精品视频 | 亚洲国产日韩精品 | 97在线观看视频 | 国产日产高清dvd碟片 | 成人性生交大片免费看中文网站 | 美女视频a美女大全免费下载蜜臀 | 黄色av网站在线观看免费 | 狠狠操导航 | 国产亚洲精品美女 | 亚洲国产午夜 | 色综合婷婷久久 | a一片一级 | 97超碰在线久草超碰在线观看 | 精品福利视频在线观看 | 亚洲精品黄色片 | 亚洲婷婷网 | 国产精品高潮呻吟久久久久 | 永久av免费在线观看 | 久久字幕精品一区 | 国产精品久久一区二区三区不卡 | 亚洲精品国产品国语在线 | 亚洲最快最全在线视频 | 国产精品精品久久久久久 | 韩国av一区| 91麻豆精品国产91久久久无需广告 | 精品主播网红福利资源观看 | 精品国模一区二区 | 97精品国产91久久久久久久 | 国产一区二区三区免费在线观看 | 五月婷av | 久久久福利 | 欧美色噜噜| 国产一区成人在线 | 欧美色图视频一区 | 亚洲免费a | 亚洲精品色婷婷 | 99精品欧美一区二区三区黑人哦 | 成人免费网站在线观看 | 91探花在线| 久久久久女教师免费一区 | 日韩免费不卡av | 懂色av一区二区三区蜜臀 | 97超碰在线播放 | 久草在线视频资源 | 免费观看www视频 | 91传媒激情理伦片 | 波多野结衣视频一区二区 | 久久久久一区二区三区四区 | av网站大全免费 | 在线观看黄色国产 | 免费观看成人网 | 日韩欧美高清在线 | 天天操天天操天天爽 | 国产亚州av | 特级大胆西西4444www | 欧美久久久久久久久久 | 中文字幕一区av | 五月花丁香婷婷 | www.香蕉视频在线观看 | 在线电影91| 亚洲精品在线视频播放 | 欧美一级久久久久 | 欧美日韩精品在线观看视频 | 欧美色综合天天久久综合精品 | 亚洲精品1234区 | 天天射天天干天天操 | 日韩视频免费观看高清 | 免费一区在线 | 丁香花在线视频观看免费 | 在线免费观看不卡av | av黄免费看 | 久久99精品久久只有精品 | 人人爽人人澡人人添人人人人 | 国偷自产视频一区二区久 | 成人欧美一区二区三区黑人麻豆 | 久久午夜羞羞影院 | 国产精品久久久久久久久免费 | 91一区一区三区 | 高清精品久久 | 狠狠狠干狠狠 | 激情影音先锋 | 五月丁色 | 成人久久18免费网站麻豆 | 狠狠狠色丁香综合久久天下网 | 日本精品视频在线播放 | 麻花豆传媒mv在线观看 | 久久草草影视免费网 | 欧美日韩视频在线观看免费 | 亚洲精品玖玖玖av在线看 | 91毛片视频 | 日韩精品一区二区三区外面 | 日韩电影中文,亚洲精品乱码 | 免费影视大全推荐 | 亚洲精品免费在线观看 | 色91在线视频 | 黄色网址国产 | 色姑娘综合天天 | 成人黄色在线 | 在线精品视频免费播放 | 日韩在线网址 | 亚洲黄色在线免费观看 | 成人在线播放视频 | 国产精品久久久久久久久久久久午夜 | 国产在线色视频 | 91视频免费网址 | aaa毛片视频| 国产99久久久久久免费看 | 欧美一级特黄aaaaaa大片在线观看 | 99精品国产高清在线观看 | 精品国内自产拍在线观看视频 | 精品福利国产 | 色中色资源站 | 国产高清视频在线观看 | 最近中文字幕免费视频 | 视频成人永久免费视频 | 开心激情网五月天 | 国产精品亚洲片在线播放 | 国产欧美日韩精品一区二区免费 | 久久久久久久综合色一本 | 日本三级在线观看中文字 | 91亚洲在线观看 | 欧美日韩免费观看一区=区三区 | 91香蕉视频好色先生 | 久久精品国产第一区二区三区 | 国产99久久九九精品免费 | 日韩在线免费视频 | www免费视频com| 亚洲综合色站 | 狠狠色丁香婷婷综合 | 亚洲精品午夜久久久久久久久久久 | 久久精品视频18 | 久久a国产 | 欧美国产日韩一区二区 | 精品亚洲免费 | 亚洲午夜精品久久久 | 久久精品免费看 | 国产午夜精品免费一区二区三区视频 | 久久丁香网 | 日本bbbb摸bbbb| 国产精品麻豆视频 | 6699私人影院| 精品国产乱码久久久久久1区2匹 | 亚洲日本在线视频观看 | 日韩久久午夜一级啪啪 | 国产日韩视频在线播放 | 99精品在线免费视频 | 最新婷婷色 | 美女黄视频免费 | 毛片网站免费 | 亚洲精品久久久久久中文传媒 | 欧美一级电影片 | 91久久精品一区 | 成人国产精品入口 | 色综合久久综合中文综合网 | 久久综合成人 | 国产xxxxx在线观看 | 夜夜爽88888免费视频4848 | 婷婷午夜激情 | 日批视频在线观看免费 | 二区在线播放 | 亚洲精品国久久99热 | 中文字幕av免费在线观看 | a级国产乱理论片在线观看 特级毛片在线观看 | 国产福利久久 | 日韩欧美在线综合网 | 成年人免费看的视频 | 人人添人人澡人人澡人人人爽 | 久久久久网站 | 午夜91在线 | 天天操比 | 久久系列| 欧美夫妻性生活电影 | 久草热久草视频 | 国产伦精品一区二区三区照片91 | 干综合网| 三级黄免费看 | 九九热在线免费观看 | 成人午夜电影免费在线观看 | 亚洲九九爱 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 亚洲电影在线看 | 久久久久99精品国产片 | 在线视频一区二区 | 久久精品一二三区白丝高潮 | 91尤物国产尤物福利在线播放 | 亚洲黄色免费网站 | 亚洲欧美成人在线 | 热99在线 | 91精品1区2区 | 人人爱人人做人人爽 | 日日操网 | 91亚洲免费 | 日韩资源在线播放 | av先锋影音少妇 | 国内成人精品视频 | 五月视频 | www.狠狠操.com | 福利视频午夜 | 99精品视频在线观看视频 | 欧美日韩中文视频 | 99久久久久久久久久 | 国产香蕉97碰碰久久人人 | 国产精品久久久久久69 | 国产在线视频一区二区三区 | 欧美福利视频 | 国内久久精品视频 | 国产精品wwwwww | 99久久久久久国产精品 | 久久久久久久久久久久影院 | 国产成人在线看 | 麻豆影视在线免费观看 | 在线韩国电影免费观影完整版 | 日韩欧美精品一区二区 | 国产精品入口麻豆 | 久久久国产精品人人片99精片欧美一 | 精品在线观看一区二区 | 国产成人亚洲在线观看 | 在线观看国产高清视频 | 婷婷网在线 | 操久在线| 91精品视频免费在线观看 | 欧美综合久久久 | 欧美日韩在线网站 | 欧美91精品国产自产 | 日本精品久久久久 | 五月天久久久久久 | 最近中文字幕免费大全 | 日韩欧美在线观看一区 | 天天综合网入口 | 国产一区二区三区在线免费观看 | 亚洲综合一区二区精品导航 | 色婷婷综合久久久中文字幕 | 国产精品99久久久精品 | 超碰人人超碰 | 99精品国产在热久久 | 欧美精品成人在线 | 91最新视频| 亚洲在线免费视频 | 在线视频观看91 | 又黄又爽又色无遮挡免费 | 国产护士av | 日韩av电影中文字幕在线观看 | 日韩电影中文字幕在线 | 国产亚洲视频中文字幕视频 | 看片网站黄色 | 操操综合 | 欧美视频xxx | 狠狠网亚洲精品 | 亚洲精品午夜国产va久久成人 | 九色porny真实丨国产18 | 午夜国产一区 | 天天操天天干天天综合网 | 婷婷六月综合网 | 日日噜噜噜噜夜夜爽亚洲精品 | 亚洲日本va午夜在线影院 | 99热999 | 国产精品尤物视频 | 一区二区三区在线免费 | 西西人体4444www高清视频 | 九九久久免费 | 91精品爽啪蜜夜国产在线播放 | 亚洲国产中文字幕在线观看 | 亚洲欧美日本一区二区三区 | 在线观看av不卡 | 在线日本看片免费人成视久网 | 99久久久久久久 | 91亚洲精品久久久蜜桃 | 在线观看免费av网 | 美女在线免费观看视频 | 天天做天天爱夜夜爽 | 亚洲影院国产 | 97超在线| 手机成人av在线 | 狠狠插天天干 | 日韩在线免费观看视频 | 国产免费黄视频在线观看 | 成人av视屏 | 337p西西人体大胆瓣开下部 | 五月婷婷操| 国产精品黄色影片导航在线观看 | 免费电影一区二区三区 | 天天拍天天操 | 免费网站在线观看成人 | 色网站免费在线观看 | 国产成人福利在线观看 | 日韩v在线| 色噜噜在线观看视频 | 亚洲自拍偷拍色图 | 国产中文字幕在线看 | 亚洲综合在线视频 | 91日韩精品视频 | 色综合www| 日日夜夜亚洲 | 天天色天天上天天操 | 一级欧美一级日韩 | 在线国产视频一区 | 91精品国产91热久久久做人人 | 人操人 | 色综久久| 免费亚洲视频在线观看 | 久久热亚洲 | 亚洲毛片久久 | 天天操夜夜摸 | 国产精品久久精品 | 欧美激情xxxx性bbbb | 在线91精品| 999免费视频| 日韩在线播放欧美字幕 | 国产中文字幕视频在线观看 | 日本中文字幕在线观看 | 狠狠躁日日躁狂躁夜夜躁av | 欧洲不卡av | 日本在线h| 伊人资源视频在线 | 91亚·色| 精品国产自在精品国产精野外直播 | 性色av免费观看 | 婷婷色网址| www.狠狠色.com | 亚洲 欧美 变态 国产 另类 | 一区二区三区在线视频111 | 成人h电影| 国产一级片播放 | 五月综合激情 | 亚洲爱av| 国产最顶级的黄色片在线免费观看 | 午夜色大片在线观看 | 好看av在线 | 在线99视频 | 久久69精品久久久久久久电影好 | 日日夜夜天天综合 | 高清不卡免费视频 | 日韩在线无| 精品亚洲免费视频 | 日韩欧美综合视频 | 日韩激情一二三区 | 在线观看视频亚洲 | 国产成人久 | avav99 | 黄色av一级片 | 99久久精品视频免费 | 久久在线精品视频 | 在线观看深夜视频 | 黄色av一区二区三区 | 亚洲 在线| 日韩中出在线 | 中文字幕一区二区在线观看 | 亚洲欧美999 | 91精品国 | 中文字幕视频一区 | 国产精品免费久久久久 | 一区二区精品国产 | 欧美日韩不卡一区 | 狠狠干激情 | 午夜在线免费观看 | 精品在线视频一区二区三区 | 精品福利在线视频 | 五月天婷婷视频 | 欧美成人在线网站 | 国产精品3 | 香蕉影视 | 精品视频一区在线观看 | 亚洲国产伊人 | 成人啪啪18免费游戏链接 | 亚洲综合色视频在线观看 | 九九精品视频在线观看 | 五月开心婷婷网 | 国产四虎在线 | 中文国产字幕在线观看 | 亚洲资源| 国产精品久久久久久久久久久杏吧 | 欧美性高跟鞋xxxxhd | 91福利视频在线 | wwwwwww黄| 99久久这里只有精品 | 天天干天天操天天拍 | 午夜黄色大片 | 在线观看一区二区精品 | 中文字幕免费在线看 | 久久99精品一区二区三区三区 | 99av在线视频 | 日韩精品一区二区在线观看视频 | 欧美成人性战久久 | 亚洲精品一区二区三区在线观看 | a在线v | 欧美片一区二区三区 | 国产伦精品一区二区三区免费 | 精品1区2区3区 | 天天综合操 | 国产免费a | 一区二区精品在线观看 | 午夜丰满寂寞少妇精品 | 91久久偷偷做嫩草影院 | 精品久久久久久亚洲综合网站 | 亚洲一级电影视频 | 国产午夜麻豆影院在线观看 | 91系列在线观看 | 在线观av| 午夜性生活片 | 一级片免费在线 | 久久成人免费电影 | 很污的网站 | 精品久久影院 | 四虎国产精品免费 | 国产特级毛片aaaaaa | 日本久久久久久科技有限公司 | 成人国产综合 | 午夜少妇 | 亚洲国产精品成人精品 | 久久精品男人的天堂 | 午夜久久福利视频 | 免费a v视频| 亚洲乱码久久 | 看片的网址 | 免费看片成人 | 天海冀一区二区三区 | 国产中文字幕在线 | 免费亚洲视频在线观看 | www色网站| 天天操综| 日韩久久精品一区二区三区 | 中文字幕影片免费在线观看 | av在线免费观看黄 | 欧美另类美少妇69xxxx | 91精品国产电影 | 国产一区视频免费在线观看 | 久草精品视频在线观看 | 天堂av在线免费 | 婷婷色婷婷 | 免费观看久久久 | 亚洲人人网 | 日韩欧美69| 91人人澡人人爽人人精品 | 色www精品视频在线观看 | 亚洲日本在线视频观看 | 国产亚洲精品久久 | 国产专区在线 | 黄色三级久久 | 日韩中字在线 | 狠狠干夜夜操天天爽 | 波多野结衣亚洲一区二区 | 日韩欧美在线观看 | 91在线麻豆 | 黄色一区三区 | 日韩深夜在线观看 | 久久久影片 | 成人影片在线免费观看 | 在线看片视频 | 欧美激情第八页 | 国产中文欧美日韩在线 | 亚洲精品网址在线观看 | www.91成人 | 午夜国产福利在线 | 久久久精品视频网站 | 亚洲国产天堂av | 500部大龄熟乱视频使用方法 | 啪啪午夜免费 | 国产玖玖在线 | 成人国产精品久久久春色 | 欧美午夜性生活 | 伊人宗合| 久久久精品日本 | 视频1区2区| 麻豆成人精品视频 | 国产精彩视频一区二区 | 亚洲天堂网在线视频观看 | 97在线精品 | 国产在线精品二区 | 91视频久久久久久 | 91精品国产自产老师啪 | 午夜精品久久久99热福利 | 波多野结衣在线视频免费观看 | 国产亚洲精品久久 | 在线观看免费中文字幕 | 亚洲欧美日本A∨在线观看 青青河边草观看完整版高清 | 日本黄区免费视频观看 | 国产精在线 | 91精品办公室少妇高潮对白 | 狠狠躁日日躁夜夜躁av | 久久免费视频4 | 日日碰狠狠躁久久躁综合网 | 国产高清av免费在线观看 | 亚洲天堂首页 | 国产精品福利午夜在线观看 | 在线观看中文字幕一区 | 国产精品久久久久久久久搜平片 | 精品久久久久久久久久久院品网 | 亚洲精品午夜久久久久久久 | 亚洲视频资源在线 | 精品一区在线看 | 久久99视频 | 亚洲综合网站在线观看 | 免费观看9x视频网站在线观看 | 亚洲国产日韩在线 | 久久av网址 | 国产精品毛片一区视频播不卡 | 在线电影 你懂得 | 九色免费视频 | a级国产乱理论片在线观看 特级毛片在线观看 | mm1313亚洲精品国产 | 二区在线播放 |